Ë
    âß²j€�  ã            
      ó0  — d Z ddlmZ ddlZddlZddlZddlZddlmZm	Z	m
Z
mZmZ ddlmZmZmZmZmZmZmZmZ  ej.                  d«      ZdZd ed	d
«      › d ed	d«      › d ej4                  d¬«      › d ed«      › d�	Zdd„Z	 	 dd„Z G d„ d«      Zy)zÝCompression lineage, cooldown/streak counters, locks and turn leases for SessionDB.

Mixin bound onto ``SessionDB`` via the MRO, built on its ``_read_ctx`` /
``_execute_write`` / ``_write_sql`` / ``_read_one`` primitives.é    )ÚannotationsN)ÚAnyÚDictÚListÚOptionalÚTuple)Ú_BOUNDARY_END_REASONSÚ_COMPRESSION_LOCK_ROW_SQLÚ_ENDED_ROW_SQLÚ_ended_by_compressionÚ_RESET_CHILD_SQLÚ_sql_json_extractÚ_sql_session_last_activeÚis_automatic_end_reasonÚhermes_statez_SELECT compression_failure_cooldown_until, compression_failure_error FROM sessions WHERE id = ?a  
                    SELECT child.id
                    FROM sessions parent
                    JOIN sessions child ON child.parent_session_id = parent.id
                    WHERE parent.id = ?
                      AND parent.end_reason = 'compression'
                      AND zchild.model_configz$._branched_fromz# IS NULL
                      AND z$._delegate_fromz( IS NULL
                      AND NOT (Úchild)ÚaaI  )
                      AND COALESCE(child.source, '') != 'tool'
                    ORDER BY
                      CASE
                        WHEN child.end_reason = 'compression' THEN 0
                        WHEN child.ended_at IS NULL THEN 1
                        ELSE 2
                      END,
                      zˆ DESC,
                      child.started_at DESC,
                      child.id DESC
                    LIMIT 1
                    c                ó.   — | |�t        |«      |dœS d |dœS )N)Úsession_existsÚcooldown_untilÚerror©Úfloat)Úexistsr   r   s      ú=/home/ubuntu/.hermes/hermes-agent/hermes_state_compression.pyÚ_cooldown_rowr   4   s3   € Ø$Ø7EÐ7Qœe NÓ3Ðfkñmð mØW[Ðfkñmð mó    c                óh  — d}| j                  d|› d|› d�|f«      j                  «       }	|	�2 ||	d   |	d   «      r#| j                  d|› d|› d�||	d   f«       |	d   }| j                  d	|› d
|› d�||||f«       | j                  d|› d|› d�|f«      j                  «       }
|
duxr |
d   |k(  |fS )zóSingle-transaction lease claim: DELETE a stale holder's row (``stale(holder,
    expires_at)``), INSERT OR IGNORE ours, then SELECT to confirm ownership (INSERT OR
    IGNORE gives no rowcount signal). Returns ``(acquired, reclaimed_holder)``.NzSELECT holder, expires_at FROM z WHERE z = ?ÚholderÚ
expires_atzDELETE FROM z = ? AND holder = ?zINSERT OR IGNORE INTO z (z6, holder, acquired_at, expires_at) VALUES (?, ?, ?, ?)zSELECT holder FROM )ÚexecuteÚfetchone)ÚconnÚtableÚkey_colÚkeyr   Únowr    ÚstaleÚreclaimed_holderÚrowÚowners              r   Ú_claim_lease_rowr,   9   sú   € ð
 ÐØ
�,‰,Ð8¸¸¸wÀwÀiÈtÐTÐWZÐV\Ó
]×
fÑ
fÓ
h€CØ
€™5  X¡°°LÑ0AÔBØ�‰�| E 7¨'°'°Ð:MÐNÐQTÐVYÐZbÑVcÐPdÔeØ˜x™=ÐØ‡L�LØ
    r¨'¨Ð2hÐiØ	ˆf�c˜:Ð&ô(ð �L‰LÐ.¨u¨g°W¸W¸IÀTÐJÈSÈFÓS×\Ñ\Ó^€EØ˜ÐÒ:  x¡°FÑ!:Ð<LÐLÐLr   c                  óö  — e Zd ZdZddœ	 	 	 	 	 	 	 d1d„Zd2d„Zd3d„Z	 	 d4d„Zdddddddd	d
dddœ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d5d„Zd6d„Z		 d7	 	 	 	 	 	 	 d8d„Z
d9d„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dAd„ZdBd„ZdCd„ZdDdEd„ZdDdEd„ZdFd„ZdGd„ZdGd„Zd
dd œ	 	 	 	 	 	 	 	 	 dHd!„Zd
d"d#dd$dd%d&œ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dId'„Zd
d(œdEd)„ZdFd*„ZdJd+„Z dKd,„Z!dLd-„Z"dJd.„Z#dMd/„Z$dLd0„Z%y)NÚSessionCompressionMixinzECompression lineage, cooldown/streak counters, locks and turn leases.N©Ú
patience_sc               óv   ‡ ‡— ‰syˆ ˆfd„}‰ j                  ||¬«      }|�t        j                  d‰||«       |S )aT  Clear an explicit-close stamp (``tui_close``, ``cli_close``, ``webhook_complete``, ...) from a
        session a HOST has just proven is still routed to it, returning the reason cleared or None (#106459).
        Narrow twin of ``reopen_session()``: automatic stamps are left to publish (#88197); ``compression``,
        boundary (reset reasons, CLI ``new_session``) and stamps with a published continuation own lineage
        elsewhere and are never touched. The UPDATE is conditional on the exact stamp read, so a close
        landing between read and write survives.

        Only the routing host can make this call. Publication cannot: ``end_session()`` is first-stamp-wins,
        so a close made during a turn that began on a stale stamp is a no-op write. Turn-lease admission
        cannot: the TUI starts its worker before it reaches ``run_conversation()``, so ``session.close`` can
        stamp ``tui_close`` in between and a late lease would clear a deliberate close. Call it under the
        lock that makes the host's registry claim atomic with its teardown (#54878 on the routing table).Nc                ón  •— | j                  t        ‰f«      j                  «       }|�|d   €y |d   }t        |«      s|dk(  s|t        v ry | j                  d‰j
                  j                  d¬«      z   dz   ‰fdz  «      j                  «       }|�y | j                  d	‰|d   |f«       t        |«      S )
NÚended_atÚ
end_reasonÚcompressionz2SELECT 1 FROM sessions WHERE parent_session_id = ?Ú ©Úaliasz LIMIT 1é   zgUPDATE sessions SET ended_at = NULL, end_reason = NULL WHERE id = ? AND ended_at = ? AND end_reason = ?)r!   r   r"   r   r	   Ú"_NON_CONTINUATION_CHILD_FILTER_SQLÚformatÚstr)r#   r*   ÚreasonÚ
supersededÚselfÚ
session_ids       €€r   Ú_doz@SessionCompressionMixin.reopen_if_explicitly_closed.<locals>._do_   s×   ø€ Ø—,‘,œ~°
¨}Ó=×FÑFÓHˆCØˆ{˜c *™oÐ5ØØ˜Ñ&ˆFÜ& vÔ.°&¸MÒ2IÈVÔWlÑMlØØŸ™ØDØ×9Ñ9×@Ñ@ÀrÐ@ÓJñKØMWñXà� Ñ!ó#÷ $,¡8£:ð ð Ð%ØØ�L‰LðCà˜S ™_¨fÐ5ô7ô �v“;Ðr   r/   z‚Session %s carried a stale %r end stamp while %s; cleared so the conversation can compress and a later close is recorded (#106459))Ú_execute_writeÚloggerÚwarning)r?   r@   Ú
provenancer0   rA   r=   s   ``    r   Úreopen_if_explicitly_closedz3SessionCompressionMixin.reopen_if_explicitly_closedM   sP   ù€ ñ Øõ	ð$ ×$Ñ$ S°ZÐ$Ó@ˆØÐÜ�N‰NðCØDNÐPVÐXbôdð ˆr   c                ó’  — |sy| j                  «       5 }t        |j                  t        |f«      j	                  «       «      s
	 ddd«       y|j                  d| j
                  j                  d¬«      z   dz   |fdz  «      j                  «       }ddd«       t        «      dk(  r| j                  |d   «      S dS # 1 sw Y   Œ-xY w)	zëThe unique live direct child of a compression-ended session, else None. A stale
        agent whose parent was rotated elsewhere may recover only when the lineage names
        exactly one live continuation; more than one fails closed.Nad  
                SELECT s.*,
                       COALESCE(sp.prompt, s.system_prompt)
                           AS _system_prompt_resolved
                FROM sessions s
                LEFT JOIN system_prompts sp ON sp.hash = s.system_prompt_hash
                WHERE s.parent_session_id = ?
                  AND s.ended_at IS NULL
                zs.r7   zS
                ORDER BY s.started_at ASC
                LIMIT 2
                r9   é   r   )
Ú	_read_ctxr   r!   r   r"   r:   r;   ÚfetchallÚlenÚ_session_row_dict)r?   Úparent_session_idr#   Úrowss       r   Úfind_live_compression_childz3SessionCompressionMixin.find_live_compression_childx   sÕ   € ñ !ØØ�^‰^Óð 	 Ü(¨¯©´nÐGXÐFZÓ)[×)dÑ)dÓ)fÔgØ÷	ð 	ð —<‘<ðð ×9Ñ9×@Ñ@ÀtÐ@ÓLñ	Mðñð #Ð$ qÑ(ó÷  ‰h‹jð! ÷	ô( 36°d³)¸q².ˆt×%Ñ% d¨1¡gÓ.ÐJÀdÐJ÷)	ð 	ús   ”0B=ÁAB=Â=Cc                óL   ‡ ‡— ‰syˆ ˆfd„}t        ‰ j                  |«      «      S )zöReopen a compression parent only when no continuation was published (older
        builds could leave a closed parent after an interrupted handoff). Conservative:
        an active lease or any canonical child means another path owns the lineage.Fc                ó&  •— t        | j                  t        ‰f«      j                  «       «      sy| j                  d‰j                  j                  d¬«      z   dz   ‰fdz  «      j                  «       }|�yt        j                  «       }| j                  t        ‰f«      j                  «       }|�>|d   }|�t        |«      |k\  ry| j                  d‰|d	   |f«      }|j                  d
k7  ry| j                  d‰f«      }|j                  d
k(  S )NFzt
                SELECT 1
                FROM sessions
                WHERE parent_session_id = ?
                r6   r7   z)
                LIMIT 1
                r9   r    zTDELETE FROM compression_locks WHERE session_id = ? AND holder = ? AND expires_at = ?r   rH   z{UPDATE sessions SET ended_at = NULL, end_reason = NULL WHERE id = ? AND ended_at IS NOT NULL AND end_reason = 'compression')
r   r!   r   r"   r:   r;   ÚtimeÚ_LOCK_ROW_SQLr   Úrowcount)	r#   r   r'   Úlock_rowr    ÚdeletedÚupdatedr?   r@   s	          €€r   rA   zHSessionCompressionMixin.reopen_orphaned_compression_session.<locals>._doš   s0  ø€ Ü(¨¯©´nÀzÀmÓ)T×)]Ñ)]Ó)_Ô`Øà—L‘Lðð
 ×9Ñ9×@Ñ@ÀrÐ@ÓJñKðñð � Ñ!ó÷ ‰h‹jð ð Ð Øô —)‘)“+ˆCØ—|‘|¤M°J°=ÓA×JÑJÓLˆHØÐ#Ø% lÑ3�
ØÐ%¬¨zÓ):¸cÒ)AØ ØŸ,™,ØjØ ¨(Ñ!3°ZÐ@óB�ð ×#Ñ# qÒ(Ø Ø—l‘lðWà�óˆGð  ×#Ñ# qÑ(Ð(r   )ÚboolrB   )r?   r@   rA   s   `` r   Ú#reopen_orphaned_compression_sessionz;SessionCompressionMixin.reopen_orphaned_compression_session”   s)   ù€ ñ Øõ0	)ôb �D×'Ñ'¨Ó,Ó-Ð-r   c               ó8  — | j                  ||«      }|j                  d||||rt        j                  |«      nd|||	xs |d   |d   |d   |
xs |d   xs | j	                  «       |d   |d   |d	   |d
   |d   |d   |d   t        j
                  «       f«       y)a  INSERT the compression child's ``sessions`` row copied from *parent*. Same contract as
        _insert_session_row's compression-fork backfill: the child stays on the parent's profile and keeps
        gateway routing/origin columns; no owner on either side -> this store's profile.a«  INSERT INTO sessions (
                   id, source, model, model_config, system_prompt,
                   system_prompt_hash,
                   parent_session_id, cwd, git_branch, git_repo_root,
                   profile_name, user_id, session_key, chat_id, chat_type,
                   thread_id, display_name, origin_json, started_at
                ) VALUES (?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)NÚcwdÚ
git_branchÚgit_repo_rootÚprofile_nameÚuser_idÚsession_keyÚchat_idÚ	chat_typeÚ	thread_idÚdisplay_nameÚorigin_json)Ú_store_system_promptr!   ÚjsonÚdumpsÚ_own_profile_namerR   )r?   r#   ÚparentrM   Úchild_session_idÚsourceÚmodelÚmodel_configÚsystem_promptr[   r^   Úsystem_prompt_hashs               r   Ú_publish_child_session_rowz2SessionCompressionMixin._publish_child_session_rowÍ   sÄ   € ð
 "×6Ñ6°t¸]ÓKÐØ�‰ðYð ! &¨%É\´·±¸LÔ1IÐ_cØ"Ð$5°sÒ7K¸fÀU¹mÈVÐT`ÑMaØ�Ñ'ØÒR  ~Ñ 6ÒR¸$×:PÑ:PÓ:RØ�yÑ! 6¨-Ñ#8¸&ÀÑ:KÈVÐT_ÑM`Ø�{Ñ# V¨NÑ%;¸VÀMÑ=RÔTX×T]ÑT]ÓT_ðaõ	
r   TFç     Àr@)rm   rn   ro   r[   r^   Úcompression_lock_holderÚrequire_compression_leaseÚrequire_lease_refreshÚlease_ttl_secondsÚ	watermarkÚwatermark_ceilingc               ó~   ‡ ‡‡‡‡‡‡‡‡‡	‡
‡‡‡‡‡‡— ddl mŠ ˆˆˆ
ˆˆˆˆˆˆˆ	ˆˆˆ ˆˆˆˆfd„}‰ j                  |«       y)u$  Atomically close a parent and publish its durable compression child: closure, child row, and
        handoff commit in one transaction, so readers see the live parent or a complete child, never an
        ended parent with a missing/empty child. *watermark* (parent's ``get_active_message_watermark`` at compression start): parent rows with ``id
        > watermark`` â€” appends landed during the slow summary â€” are column-cloned into the child AFTER the
        handoff. *watermark_ceiling* bounds the clone: the rotation path flushes its OWN transcript to the
        parent just before publishing and those rows are already in the handoff, so only ``(watermark,
        watermark_ceiling]`` is foreign tail (``None`` = unbounded). *require_lease_refresh* +
        *compression_lock_holder* refreshes the lease on the same ``conn`` before the expiry check (no
        TOCTOU window), so a refresher that died on transient DB errors gets one last chance.

        See #75316.
        ``None`` = unbounded (no internal flush happened). See #47202.
        r   )ÚCompressionSessionBusyErrorc                óê  •— ‰r,‰r*| j                  dt        j                  «       ‰z   ‰‰f«       | j                  t        ‰f«      j                  «       }‰r:|�-‰r+|d   ‰k7  s#t	        |d   «      t        j                  «       k  r ‰	d‰› �«      ‚| j                  d‰f«      j                  «       }|€t        d‰› �«      ‚|d   �/t        |d   «      st        d	‰› �«      ‚| j                  d
‰f«       ‰st        d«      ‚‰j                  | |‰‰
‰‰‰‰‰‰¬«
       ‰j                  | ‰
‰«      \  }}‰�f‰d u}‰j                  | d|rdnd› d�‰t        ‰«      g|rt        ‰«      gng ¢«      \  }}|r'‰j                  | |‰
¬«       |t        |«      z  }||z  }| j                  d||‰
f«       | j                  dt        j                  «       ‰f«      }|j                  dk7  rt        d‰› �«      ‚y )NúOUPDATE compression_locks SET expires_at = ? WHERE session_id = ? AND holder = ?r   r    z+Compression lease lost before publication: zûSELECT ended_at, end_reason, cwd, git_branch, git_repo_root,
                          user_id, session_key, chat_id, chat_type,
                          thread_id, display_name, origin_json, profile_name
                   FROM sessions WHERE id = ?zCompression parent not found: r3   r4   z"Compression parent already ended: zCUPDATE sessions SET ended_at = NULL, end_reason = NULL WHERE id = ?z+Compression child handoff must not be empty)rM   rk   rl   rm   rn   ro   r[   r^   zRSELECT id, tool_calls FROM messages WHERE session_id = ? AND active = 1 AND id > ?z AND id <= ?r6   z ORDER BY id)r@   zGUPDATE sessions SET message_count = ?, tool_call_count = ? WHERE id = ?z^UPDATE sessions SET ended_at = ?, end_reason = 'compression' WHERE id = ? AND ended_at IS NULLrH   z/Compression parent changed during publication: )r!   rR   rS   r"   r   ÚRuntimeErrorr   rq   Ú_insert_message_rowsÚ_tail_rows_after_watermarkÚintÚ_clone_message_rowsrK   rT   )r#   rU   rj   Útotal_messagesÚtotal_tool_callsÚboundedÚtail_idsÚtail_tool_callsrW   rz   rk   rs   r[   rv   Úmessagesrm   rn   rM   r^   rt   ru   r?   rl   ro   rw   rx   s            €€€€€€€€€€€€€€€€€r   rA   z>SessionCompressionMixin.publish_compression_child.<locals>._doù   s„  ø€ Ù$Ñ)@Ø—‘ØeÜ—Y‘Y“[Ð#4Ñ4Ð6GÐI`Ðaôcð —|‘|¤MÐ4EÐ3GÓH×QÑQÓSˆHÙ(ØÐ Ñ(?Ø˜HÑ%Ð)@Ò@Ü˜ ,Ñ/Ó0´D·I±I³KÒ?á1ØAÐBSÐATÐUóWð Wà—\‘\ð1ð #Ð$ó÷ ‰h‹jð ð ˆ~Ü"Ð%CÐDUÐCVÐ#WÓXÐXØ�jÑ!Ð-ô
 /¨v°lÑ/CÔDÜ&Ð)KÐL]ÐK^Ð'_Ó`Ð`Ø—‘ØYØ&Ð(ô*ñ Ü"Ð#PÓQÐQØ×+Ñ+Ø�fÐ0AÐTdØ U¸ÐUbØ lð ,ô 4ð 04×/HÑ/HÈÐO_ÐaiÓ/jÑ,ˆNÐ,ØÐ$ð ,°4Ð7�Ø,0×,KÑ,KØð Eá)0‘~°bÐ9¸ðGð '¬¨I«ÐgÑV]¼3Ð?PÓ;QÑ:RÐceÐgó	-iÑ)�˜/ñ
 Ø×,Ñ,¨T°8ÐHXÐ,ÔYØ"¤c¨(£mÑ3�NØ$¨Ñ7Ð$Ø�L‰LØYØÐ!1Ð3CÐDôFð —l‘lð4Ü6:·i±i³kÐCTÐ5UóWˆGð ×Ñ 1Ò$Ü"Ð%TÐUfÐTgÐ#hÓiÐið %r   N)Úhermes_state_errorsrz   rB   )r?   rM   rk   rl   r‡   rm   rn   ro   r[   r^   rs   rt   ru   rv   rw   rx   rA   rz   s   ```````````````` @r   Úpublish_compression_childz1SessionCompressionMixin.publish_compression_childä   s.   ÿÿø€ õ( 	D÷;	j÷ ;	jô ;	jðx 	×Ñ˜CÕ r   c                óš   — 	 | j                  ||«       y# t        j                  $ r"}t        j	                  d|||«       Y d}~yd}~ww xY w)z=``_write_sql`` that logs (never raises) on ``sqlite3.Error``.z%s(%s) failed: %sN)Ú
_write_sqlÚsqlite3ÚErrorrC   rD   )r?   Úopr@   ÚsqlÚparamsÚexcs         r   Ú_write_sql_loggedz)SessionCompressionMixin._write_sql_logged7  sB   € ð	EØ�O‰O˜C Õ(øÜ�}‰}ò 	EÜ�N‰NÐ.°°JÀ×DÑDûð	Eús   ‚ •A
¨AÁA
c           	     ó:   — |sy| j                  d|d||||f«       y)zÃPersist the active compression-failure cooldown. Merge-max with any longer live deadline so a
        later shorter write can't reopen the thrash window; error always takes the latest diagnostic.NÚ#record_compression_failure_cooldownzüUPDATE sessions SET compression_failure_cooldown_until = CASE WHEN compression_failure_cooldown_until IS NOT NULL  AND compression_failure_cooldown_until > ? THEN compression_failure_cooldown_until ELSE ? END, compression_failure_error = ? WHERE id = ?©r’   )r?   r@   r   r   s       r   r”   z;SessionCompressionMixin.record_compression_failure_cooldown>  s2   € ñ ØØ×ÑØ1°:ðmð ˜^¨U°JÐ?õ	Ar   c                óÚ   — t        j                   «       }|r| j                  t        |f«      nd}|�|d   �t        |d   «      |k  ryt        |d   «      t        |d   «      |z
  |d   dœS )zDReturn the active (unexpired) compression-failure cooldown, or None.Nr   rH   )r   Úremaining_secondsr   )rR   Ú	_read_oneÚ_COOLDOWN_ROW_SQLr   )r?   r@   r'   r*   s       r   Ú get_compression_failure_cooldownz8SessionCompressionMixin.get_compression_failure_cooldownM  so   € ä�i‰i‹kˆÙBLˆd�n‰nÔ.°°Ô>ÐRVˆØˆ;˜#˜a™&˜.¬E°#°a±&«M¸SÒ,@ØÜ"'¨¨A©£-ÄeÈCÐPQÉFÃmÐVYÑFYÐdgÐhiÑdjÑkÐkr   c                ó|   — |r| j                  t        |f«      nd}|€t        ddd«      S t        d|d   |d   «      S )z˜Exact stored cooldown columns, no expiry filtering, so compression cancellation
        can roll back an expired, partially-null, or absent row exactly.NFTr   rH   )r˜   r™   r   ©r?   r@   r*   s      r   Ú$get_compression_failure_cooldown_rowz<SessionCompressionMixin.get_compression_failure_cooldown_rowU  sN   € ñ CMˆd�n‰nÔ.°°Ô>ÐRVˆØ36°;Œ}˜U D¨$Ó/ÐgÄMÐRVÐX[Ð\]ÑX^Ð`cÐdeÑ`fÓDgÐgr   c                óä  ‡‡‡— |j                  dd«      s-| j                  ‰«      j                  dd«      rt        d«      ‚y|j                  d«      Š|j                  d«      Šˆˆˆfd„}| j                  |«      st        j                  d‰«       y| j                  ‰«      }t        d	‰‰«      }||k7  r:|j                  dd«      st        j                  d
‰«       yt        d|›d|›�«      ‚y)u°  Restore and verify an exact cooldown-row snapshot. Unlike record/clear this
        rollback API propagates write and verification failures: cancellation must not be
        reported mutation-free when compensation failed. The tolerated exception is a
        session row that vanished mid-attempt â€” before or after the compensating write â€”
        since its cooldown died with it and there is nothing left to restore (#106271).r   FzBcannot restore absent compression cooldown row: session now existsNr   r   c                óL   •— | j                  d‰‰‰f«      }|j                  dk(  S )NzfUPDATE sessions SET compression_failure_cooldown_until = ?, compression_failure_error = ? WHERE id = ?rH   )r!   rT   )r#   ÚcursorÚdeadliner   r@   s     €€€r   rA   zMSessionCompressionMixin.restore_compression_failure_cooldown_row.<locals>._dog  s3   ø€ Ø—\‘\ð=Ø?GÈÐPZÐ>[ó]ˆFð —?‘? aÑ'Ð'r   z1compression cooldown rollback session missing: %sTz?compression cooldown rollback session missing after restore: %sz<compression cooldown rollback verification failed: expected=z	, actual=)Úgetr�   r}   rB   rC   rD   r   )r?   r@   ÚsnapshotrA   ÚactualÚexpectedr¡   r   s    `    @@r   Ú(restore_compression_failure_cooldown_rowz@SessionCompressionMixin.restore_compression_failure_cooldown_row[  sô   ú€ ð �|‰|Ð,¨eÔ4Ø×8Ñ8¸ÓD×HÑHÐIYÐ[`ÔaÜ"Ð#gÓhÐhØØ—<‘<Ð 0Ó1ˆØ—‘˜WÓ%ˆö	(ð
 ×"Ñ" 3Ô'Ü�N‰NÐNÐPZÔ[ØØ×:Ñ:¸:ÓFˆÜ   x°Ó7ˆØ�XÒØ—:‘:Ð.°Ô6Ü—‘Ð`ÐblÔmØÜØNÈxÈlÐZcÐdjÐcmÐnópð pð	 r   c                ó4   — |sy| j                  d|d|f«       y)z?Clear any persisted compression-failure cooldown for a session.NÚ"clear_compression_failure_cooldownzlUPDATE sessions SET compression_failure_cooldown_until = NULL, compression_failure_error = NULL WHERE id = ?r•   ©r?   r@   s     r   r¨   z:SessionCompressionMixin.clear_compression_failure_cooldownx  s&   € áØØ×ÑØ0°*ð<Ø>H¸]õ	Lr   c                ó¢   — |r| j                  d|› d�|f«      nd}	 |€|S t        | ||d   xs |«      «      S # t        t        f$ r |cY S w xY w)z†Read one numeric ``sessions`` column clamped at ``zero``; a missing session,
        NULL, or unparsable value also reads as ``zero``.zSELECT z FROM sessions WHERE id = ?Nr   )r˜   ÚmaxÚ	TypeErrorÚ
ValueError)r?   Úcolumnr@   ÚcastÚzeror*   s         r   Ú_read_session_numberz,SessionCompressionMixin._read_session_number�  sh   € ñ _iˆd�n‰n˜w v hÐ.IÐJÈZÈMÔZÐnrˆð	Ø˜;�4ÐK¬C°±d¸3¸q¹6º>ÀTÓ6JÓ,KÐKøÜœ:Ð&ò 	ØŠKð	ús   �: ¡: ºAÁAc                ó4   — | j                  d|› d�||f«       y )NzUPDATE sessions SET z = ? WHERE id = ?)r‹   )r?   r®   r@   Úvalues       r   Ú_write_session_columnz-SessionCompressionMixin._write_session_columnŠ  s!   € Ø�‰Ð.¨v¨hÐ6GÐHÈ5ÐR\ÐJ]Õ^r   c                ó2   — | j                  d|t        d«      S )z3Return the persisted deterministic-fallback streak.Úcompression_fallback_streakr   ©r±   r€   r©   s     r   Úget_compression_fallback_streakz7SessionCompressionMixin.get_compression_fallback_streak�  s   € à×(Ñ(Ð)FÈ
ÔTWÐYZÓ[Ð[r   c           
     óV   — |r'| j                  d|t        dt        |«      «      «       yy)z:Persist the deterministic-fallback streak for one session.r¶   r   N©r´   r«   r€   )r?   r@   Ústreaks      r   Úset_compression_fallback_streakz7SessionCompressionMixin.set_compression_fallback_streak‘  s-   € áØ×&Ñ&Ð'DÀjÔRUÐVWÔY\Ð]cÓYdÓReÕfð r   c                ó2   — | j                  d|t        d«      S )uä   Persisted ineffective-compaction strike count â€” the durable half of the built-in
        compressor's anti-thrash guard, so a fresh compressor bound to a resumed session
        inherits an armed/tripped guard across restarts.Úcompression_ineffective_countr   r·   r©   s     r   Ú!get_compression_ineffective_countz9SessionCompressionMixin.get_compression_ineffective_count–  s   € ð ×(Ñ(Ð)HÈ*ÔVYÐ[\Ó]Ð]r   c           
     óV   — |r'| j                  d|t        dt        |«      «      «       yy)z@Persist the ineffective-compaction strike count for one session.r¾   r   Nrº   )r?   r@   Úcounts      r   Ú!set_compression_ineffective_countz9SessionCompressionMixin.set_compression_ineffective_countœ  s-   € áØ×&Ñ&Ð'FÈ
ÔTWÐXYÔ[^Ð_dÓ[eÓTfÕgð r   c                ó2   — | j                  d|t        d«      S )a¹  Persisted anti-thrash recovery deadline (epoch; ``0.0`` = not armed). Durable
        because the gateway rebuilds the compressor every turn / cache eviction.

        The deadline is the durable half of the 14694 recovery clock: the gateway rebuilds the compressor on
        every turn / cache eviction, so a process-local deadline restarted the wait on each rebuild and a
        tripped session never earned its probe (#100185).
        Úcompression_recovery_deadlineç        )r±   r   r©   s     r   Ú!get_compression_recovery_deadlinez9SessionCompressionMixin.get_compression_recovery_deadline¡  s   € ð ×(Ñ(Ð)HÈ*ÔV[Ð]`ÓaÐar   c                óš   — |sy	 t        dt        |xs d«      «      }| j	                  d||xs d«       y# t        t        f$ r d}Y Œ+w xY w)zGPersist the anti-thrash recovery deadline; ``0`` / ``None`` disarms it.NrÅ   rÄ   )r«   r   r¬   r­   r´   )r?   r@   r¡   Ú
normalizeds       r   Ú!set_compression_recovery_deadlinez9SessionCompressionMixin.set_compression_recovery_deadline«  sY   € áØð	Ü˜S¤%¨ª°CÓ"8Ó9ˆJð 	×"Ñ"Ð#BÀJÐPZÒPbÐ^bÕcøô œ:Ð&ò 	ØŠJð	ús   …6 ¶A
Á	A
c                óÚ   — |r|syt        j                   «       |z   }	 | j                  d|||f«      dkD  S # t        j                  $ r!}t        j                  d||«       Y d}~yd}~ww xY w)u  Extend the compression lock lease if ``holder`` still owns it. Ownership is decided by ``holder``
        alone, deliberately NOT ``expires_at``: a live owner whose refresher stalled past its TTL must be
        able to revive its still-unclaimed row, otherwise it keeps compressing with no lease â€” the window in
        which a competing path can fork the lineage. It cannot resurrect a lock someone else took: SQLite
        serialises writes, so the reclaim (DELETE-expired + INSERT OR IGNORE) never interleaves with this
        UPDATE.Fr|   r   z'refresh_compression_lock(%s) failed: %sN)rR   Ú_write_rowcountrŒ   r�   rC   rD   )r?   r@   r   Úttl_secondsr    r‘   s         r   Úrefresh_compression_lockz0SessionCompressionMixin.refresh_compression_lockµ  st   € ñ ¡ØÜ—Y‘Y“[ ;Ñ.ˆ
ð	Ø×'Ñ'ØaØ˜Z¨Ð0ó2à45ñ6ð 6øô �}‰}ò 	Ü�N‰NÐDÀjÐRUÔVÜûð	ús   ž6 ¶A*Á	A%Á%A*c                óB  ‡‡‡‡	‡
— ddl mŠ ‰syt        j                  «       Š
‰
|z   Š	ˆˆ	ˆˆ
ˆfd„}	 | j                  |«      \  }}|rt        j                  d‰|«       t        |«      S # t        j                  $ r!}t        j                  d‰|«       Y d}~yd}~ww xY w)a%  Try to atomically acquire the compression lock for ``session_id``. ``False``: another holder owns
        a live lock and the caller MUST NOT compress (its rotation would split the lineage). Expired
        locks and structured holders whose local ``pid=`` is dead are reclaimed transparently.r   ©Ú(_compression_lock_holder_process_is_deadFc                ó0   •— t        | dd‰‰‰‰ˆˆfd„«      S )NÚcompression_locksr@   c                ó"   •— |‰k  xs  ‰| «      S ©N© ©ÚhÚerÐ   r'   s     €€r   ú<lambda>zSSessionCompressionMixin.try_acquire_compression_lock.<locals>._do.<locals>.<lambda>Ó  s   ø€ ˜Q ™WÒSÑ(PÐQRÓ(S€ r   )r,   )r#   rÐ   r    r   r'   r@   s    €€€€€r   rA   zASessionCompressionMixin.try_acquire_compression_lock.<locals>._doÐ  s&   ø€ Ü#ØÐ)¨<¸ÀVÈSÐR\ÜSóUð Ur   z;Reclaimed stale compression lock for session=%s (holder=%s)z+try_acquire_compression_lock(%s) failed: %sN)	r   rÐ   rR   rB   rC   rD   rX   rŒ   r�   )r?   r@   r   rÌ   rA   Úacquiredr)   r‘   rÐ   r    r'   s    ``     @@@r   Útry_acquire_compression_lockz4SessionCompressionMixin.try_acquire_compression_lockÇ  s–   ü€ õ 	JÙØÜ�i‰i‹kˆØ˜;Ñ&ˆ
÷	Uð 	Uð
		Ø)-×)<Ñ)<¸SÓ)AÑ&ˆHÐ&ÙÜ—‘Ð\Ø)Ð+;ô=ä˜“>Ð!øÜ�}‰}ò 	ä�N‰NÐHÈ*ÐVYÔZÜûð	ús   ²7A* Á*BÁ=BÂBc                ó6   — |sy| j                  d|d||f«       y)zKRelease the compression lock iff we own it; idempotent when gone/reclaimed.NÚrelease_compression_lockzADELETE FROM compression_locks WHERE session_id = ? AND holder = ?r•   )r?   r@   r   s      r   rÝ   z0SessionCompressionMixin.release_compression_lockà  s&   € áØØ×ÑØ&¨
ØOØ˜Ð õ	"r   c                ó6  ‡— |s|S dˆfd„} ||«      }|h}|r`|j                  d«      }|r||v s| j                  |d¬«      rn5 ||«      }|r|j                  d«      dk7  rn|j                  |«       |}|rŒ`|rt        |j                  d«      xs |«      S |S )	a9  Walk compression parents on ``conn`` to the conversation lease key. Must share
        the connection of the lease INSERT/UPDATE/DELETE: a failed lookup must not yield a
        child id the write then persists. Markers bind to ``parent_session_id``. Lock
        errors propagate so ``_execute_write`` can retry.c                ód   •— ‰j                  d| f«      j                  «       }|rt        |«      S d S )NzYSELECT id, parent_session_id, source, model_config, end_reason FROM sessions WHERE id = ?)r!   r"   Údict)Úsidr*   r#   s     €r   Ú_rowzESessionCompressionMixin._session_turn_lease_key_on_conn.<locals>._rowð  s6   ø€ Ø—,‘,ØkØ�óç ™›
ð ñ !$”4˜“9Ð-¨Ð-r   rM   T©Úinclude_resetr4   r5   Úid)rá   r<   )r¢   Ú_is_explicit_fork_child_rowÚaddr<   )r?   r#   r@   râ   ÚcurrentÚseenÚ	parent_idrj   s    `      r   Ú_session_turn_lease_key_on_connz7SessionCompressionMixin._session_turn_lease_key_on_conné  s°   ø€ ñ
 ØÐõ	.ñ �zÓ"ˆØˆ|ˆÙØŸ™Ð$7Ó8ˆIÙ 	¨TÑ 1°T×5UÑ5UÐV]ÐmqÐ5UÔ5rØÙ˜)“_ˆFÙ˜VŸZ™Z¨Ó5¸ÒFØØ�H‰H�YÔØˆGò ñ 8?Œs�7—;‘;˜tÓ$Ò2¨
Ó3ÐNÀJÐNr   c                óz   — |s|S | j                  «       5 }| j                  ||«      cddd«       S # 1 sw Y   yxY w)z¢Stable serialization key for every compression segment (tests/diagnostics; the
        write paths resolve it inside their own txn). Does not swallow lock errors.N)rI   rë   )r?   r@   r#   s      r   Ú_session_turn_lease_keyz/SessionCompressionMixin._session_turn_lease_key  sB   € ñ ØÐØ�^‰^Óð 	J Ø×7Ñ7¸¸jÓI÷	J÷ 	Jò 	Jús   •1±:©rÌ   r0   c               óÈ   ‡ ‡‡‡‡‡— ddl mŠ ‰r‰syt        j                  «       Š‰t        dt	        |«      «      z   Šˆˆˆˆˆ ˆfd„}t        ‰ j                  ||¬«      «      S )zÒAtomically acquire the cross-process turn lease for a conversation (keyed by the
        lineage root). The walk, the INSERT, and reclaim of expired or dead-local-PID leases
        share one write transaction.r   rÏ   Fçš™™™™™¹?c                óZ   •— ‰j                  | ‰«      }t        | dd|‰‰‰ˆˆfd„«      d   S )NÚsession_turn_leasesÚconversation_idc                ó4   •— t        |«      ‰k  xs  ‰| «      S rÔ   r   rÖ   s     €€r   rÙ   zUSessionCompressionMixin.try_acquire_session_turn_lease.<locals>._do.<locals>.<lambda>  s   ø€ œU 1›X¨™_Ò[Ñ0XÐYZÓ0[€ r   r   )rë   r,   )r#   ró   rÐ   r    r   r'   r?   r@   s     €€€€€€r   rA   zCSessionCompressionMixin.try_acquire_session_turn_lease.<locals>._do  sC   ø€ Ø"×BÑBÀ4ÈÓTˆOÜ#ØÐ+Ð->ÀÐQWÐY\Ð^hÜ[óð ñð r   r/   )r   rÐ   rR   r«   r   rX   rB   )	r?   r@   r   rÌ   r0   rA   rÐ   r    r'   s	   ```   @@@r   Útry_acquire_session_turn_leasez6SessionCompressionMixin.try_acquire_session_turn_lease  sY   ý€ õ 	JÙ¡ØÜ�i‰i‹kˆØœ3˜s¤E¨+Ó$6Ó7Ñ7ˆ
÷	ñ 	ô �D×'Ñ'¨¸
Ð'ÓCÓDÐDr   g      œ@g      ð?g      .@g      à?)rÌ   Úwait_secondsÚpoll_interval_secondsÚon_waitÚwait_notice_interval_secondsÚshould_abortÚacquire_patience_sc          
     óÌ  — ddl m}
 t        j                  «       t	        dt        |«      «      z   }d}d}t	        dt        |«      «      }	 |�
	  |«       ry	 	 | j                  ||||	¬	«      ry	 t        j                  «       }||z
  }|dk  ry|€|}|�'|�|dk(  s||z
  |k\  r	  |t	        d||z
  «      «       |}t        j                  t        t	        dt        |«      «      |«      «       Œ£# t        $ r t        j                  dd¬«       Y Œ¹w xY w# t        j                  $ r} |
|«      d
k7  r‚ Y d}~ŒÉd}~ww xY w# t        $ r t        j                  dd¬«       Y Œ©w xY w)a  Wait for a cross-process turn lease without holding a SQLite lock. ``on_wait(elapsed)`` is
        best-effort: called when the first attempt fails and about every ``wait_notice_interval_seconds``
        after. ``should_abort()`` True (e.g. ``/stop``) returns False at once.r   )Úclassify_persistence_errorrÅ   NTFz/session turn lease should_abort callback failed)Úexc_inforî   Úlockedz*session turn lease on_wait callback failedg{®Gáz„?)r   rý   rR   Ú	monotonicr«   r   Ú	ExceptionrC   Údebugrõ   rŒ   r�   ÚsleepÚmin)r?   r@   r   rÌ   rö   r÷   rø   rù   rú   rû   rý   r¡   Úwait_startedÚlast_notice_atÚnotice_everyr‘   r'   Ú	remainings                     r   Úacquire_session_turn_leasez2SessionCompressionMixin.acquire_session_turn_lease  s�  € õ 	<Ü—>‘>Ó#¤c¨#¬u°\Ó/BÓ&CÑCˆØˆØˆÜ˜3¤Ð&BÓ CÓDˆØØÐ'ðcÙ#”~Ø$ð &ðØ×6Ñ6Ø °KÐL^ð 7ô `àð`ô —.‘.Ó"ˆCØ  3™ˆIØ˜AŠ~ØØÐ#Ø"�ØÐ"ØÐ&¨,¸#Ò*=À#ÈÑBVÐ[gÒAgð^ÙœC  S¨<Ñ%7Ó8Ô9ð "%�Ü�J‰J”sœ3˜t¤UÐ+@Ó%AÓBÀIÓNÔOð= øô
 !ò cÜ—L‘LÐ!RÐ]a�LÖbðcûô —=‘=ò ñ .¨cÓ2°hÒ>Øô ?ûðûô  !ò ^Ü—L‘LÐ!MÐX\�LÖ]ð^ús<   ÁC. ÁD Â$E  Ã. DÄDÄD=Ä'D8Ä8D=Å  E#Å"E#)rÌ   c               ó¬   ‡ ‡‡‡— ‰r‰syt        j                   «       t        dt        |«      «      z   Šˆˆˆ ˆfd„}t        ‰ j	                  |«      «      S )z8Extend a turn lease only while ``holder`` still owns it.Frð   c                ól   •— ‰j                  | ‰«      }| j                  d‰|‰f«      j                  dkD  S )NzVUPDATE session_turn_leases SET expires_at = ? WHERE conversation_id = ? AND holder = ?r   )rë   r!   rT   )r#   ró   r    r   r?   r@   s     €€€€r   rA   z?SessionCompressionMixin.refresh_session_turn_lease.<locals>._doP  sD   ø€ Ø"×BÑBÀ4ÈÓTˆOØ—<‘<ð;Ø=GÈÐZ`Ð<aó÷ ‰h˜ñð r   )rR   r«   r   rX   rB   )r?   r@   r   rÌ   rA   r    s   ```  @r   Úrefresh_session_turn_leasez2SessionCompressionMixin.refresh_session_turn_leaseK  sD   û€ á¡ØÜ—Y‘Y“[¤3 s¬E°+Ó,>Ó#?Ñ?ˆ
÷	ô �D×'Ñ'¨Ó,Ó-Ð-r   c                óD   ‡ ‡‡— ‰r‰syˆˆ ˆfd„}‰ j                  |«       y)z>Release a turn lease iff ``holder`` still owns it; idempotent.Nc                óR   •— ‰j                  | ‰«      }| j                  d|‰f«       y )NzHDELETE FROM session_turn_leases WHERE conversation_id = ? AND holder = ?)rë   r!   )r#   ró   r   r?   r@   s     €€€r   rA   z?SessionCompressionMixin.release_session_turn_lease.<locals>._do\  s,   ø€ Ø"×BÑBÀ4ÈÓTˆOØ�L‰LØZØ  &Ð)õ+r   )rB   )r?   r@   r   rA   s   ``` r   Úrelease_session_turn_leasez2SessionCompressionMixin.release_session_turn_leaseX  s    ú€ á¡Øö	+ð
 	×Ñ˜CÕ r   c                óf   — |sy| j                  d|t        j                  «       f«      }|€dS |d   S )zJCurrent (non-expired) holder for ``session_id``, or None. Diagnostic only.NzMSELECT holder FROM compression_locks WHERE session_id = ? AND expires_at >= ?r   )r˜   rR   rœ   s      r   Úget_compression_lock_holderz3SessionCompressionMixin.get_compression_lock_holderc  s?   € áØØ�n‰nØ[Ð^hÔjn×jsÑjsÓjuÐ]vóxˆà�{ˆtÐ.¨¨A©Ð.r   c                ó„   — t        j                   «       dz
  }| j                  dt        j                   «       |f«      xs dS )zöMark orphaned compression continuations (parent ended by compression; child has
        messages, no end_reason/ended_at, api_call_count=0, older than 7 days) as
        ``orphaned_compression``. Non-destructive.

        Fix for #20001.
        i€:	 a  
                UPDATE sessions
                SET ended_at = ?,
                    end_reason = 'orphaned_compression'
                WHERE api_call_count = 0
                  AND end_reason IS NULL
                  AND ended_at IS NULL
                  AND started_at < ?
                  AND parent_session_id IS NOT NULL
                  AND EXISTS (
                      SELECT 1 FROM sessions p
                      WHERE p.id = sessions.parent_session_id
                        AND p.end_reason = 'compression'
                        AND p.ended_at IS NOT NULL
                  )
                  AND EXISTS (
                      SELECT 1 FROM messages m
                      WHERE m.session_id = sessions.id
                  )
                r   )rR   rË   )r?   Úcutoffs     r   Ú&finalize_orphaned_compression_sessionsz>SessionCompressionMixin.finalize_orphaned_compression_sessionsk  sF   € ô —‘“˜vÑ%ˆØ×#Ñ#ðô( —‘“˜fÐ%ó+
ò ð, ð-	r   c                óP  — |}|r|gng }t        |«      }t        d«      D ]w  }| j                  «       5 }|j                  t        |f«      j                  «       }ddd«       �|d   nd}|r||v r|c S |j                  |«       |}|j                  |«       Œy |S # 1 sw Y   ŒDxY w)až  Walk the compression-continuation chain forward: root-first through the tip (``[session_id]``
        when no continuation); ``get_compression_tip`` is the last element. A continuation is a child of
        a session with ``end_reason='compression'``. The old ``child.started_at >= parent.ended_at`` test
        was too brittle (gateway + compression races insert the real continuation before ``ended_at`` is
        written, while a stale websocket later creates a sibling that passes it). Instead exclude
        branch/delegate/tool children and prefer children that continue the chain or are still live over
        stale closed siblings such as ``ws_orphan_reap``.éd   Nrå   )ÚsetÚrangerI   r!   Ú_CHAIN_STEP_SQLr"   rç   Úappend)	r?   r@   rè   Úchainré   Ú_r#   r*   Úchild_ids	            r   Úget_compression_chainz-SessionCompressionMixin.get_compression_chain‹  s²   € ð ˆÙ$�‘	¨"ˆÜ�5‹zˆÜ�s“ò 	#ˆAØ—‘Ó!ð K TØ—l‘l¤?°W°JÓ?×HÑHÓJ�÷Kà$' O�s˜4’y¸ˆHÙ˜x¨4Ñ/Ø’Ø�H‰H�XÔØˆGØ�L‰L˜Õ"ð	#ð ˆ÷Kð Kús   ³&BÂB%	c                ó6   — | j                  |«      }|r|d   S |S )zxLive tip of a compression chain (``get_compression_chain`` semantics); the input
        id when no continuation exists.éÿÿÿÿ)r  )r?   r@   r  s      r   Úget_compression_tipz+SessionCompressionMixin.get_compression_tip¡  s%   € ð ×*Ñ*¨:Ó6ˆÙ!ˆu�R‰yÐ1 zÐ1r   c                ó´   — |j                  d«      }|r| j                  |d¬«      ry| j                  |«      }t        |xr |j                  d«      dk(  «      S )NrM   Trã   Fr4   r5   )r¢   ræ   Úget_sessionrX   )r?   r   rê   rj   s       r   Ú_is_compression_child_rowz1SessionCompressionMixin._is_compression_child_row§  sX   € Ø—I‘IÐ1Ó2ˆ	á˜D×<Ñ<¸UÐRVÐ<ÔWØØ×!Ñ! )Ó,ˆÜ�FÒH˜vŸz™z¨,Ó7¸=ÑHÓIÐIr   c                óV  ‡ — ‰ j                  |«      }|r‰ j                  |«      r|r|gS g S |}|d   h}‰ j                  |«      rF‰ j                  |d   «      }|r|d   |v rn(|}|j                  |d   «       ‰ j                  |«      rŒF|d   g}|d   h}|}|j	                  d«      dk(  rt‰ j                  d|d   f«      }	t        ˆ fd„|	D «       d«      }
|
r|
d   |v rn?|j                  |
d   «       |j                  |
d   «       |
}|j	                  d«      dk(  rŒt||v r|S |gS )z@Return compression ancestors through tip in chronological order.rå   rM   r4   r5   zŒ
                SELECT * FROM sessions
                WHERE parent_session_id = ?
                ORDER BY started_at ASC
                c              3  ój   •K  — | ]*  }‰j                  t        |«      «      sŒt        |«      –— Œ, y ­wrÔ   )r$  rà   )Ú.0r*   r?   s     €r   ú	<genexpr>zBSessionCompressionMixin.get_compression_lineage.<locals>.<genexpr>Æ  s)   øè ø€ Òf¨S¸D×<ZÑ<ZÔ[_Ð`cÓ[dÕ<eœt CŸyÑfùs   ƒ3£3N)r#  ræ   r$  rç   r¢   Ú	_read_allÚnextr  )r?   r@   ÚsessionÚrootÚ	ancestorsrj   Úlineageré   rè   rN   Ú
next_childs   `          r   Úget_compression_lineagez/SessionCompressionMixin.get_compression_lineage¯  s`  ø€ à×"Ñ" :Ó.ˆÙ˜$×:Ñ:¸7ÔCÙ#*�J�<Ð2°Ð2ØˆØ˜$‘Z�Lˆ	Ø×,Ñ,¨TÔ2Ø×%Ñ% dÐ+>Ñ&?Ó@ˆFÙ˜V D™\¨YÑ6ØØˆDØ�M‰M˜$˜t™*Ô%ð ×,Ñ,¨TÕ2ð ˜‘:�,ˆØ�T‘
ˆ|ˆØˆØ�k‰k˜,Ó'¨=Ò8Ø—>‘>ðð ˜d‘mÐ%ó'ˆDô Óf°DÔfÐhlÓmˆJÙ ¨DÑ!1°TÑ!9ØØ�N‰N˜: dÑ+Ô,Ø�H‰H�Z Ñ%Ô&Ø ˆGð �k‰k˜,Ó'¨=Ó8ð %¨Ñ/ˆwÐA°j°\ÐAr   )r@   r<   rE   r<   r0   úOptional[float]ÚreturnúOptional[str])rM   r<   r2  úOptional[Dict[str, Any]])r@   r<   r2  rX   )r2  ÚNone) rM   r<   rk   r<   rl   r<   r‡   zList[Dict[str, Any]]rm   r<   rn   úDict[str, Any]ro   r<   r[   r<   r^   r<   rs   r<   rt   rX   ru   rX   rv   r   rw   úOptional[int]rx   r7  r2  r5  )rŽ   r<   r@   r<   r�   r<   r2  r5  rÔ   )r@   r<   r   r   r   r3  r2  r5  )r@   r<   r2  r4  )r@   r<   r2  r6  )r@   r<   r£   r6  r2  r5  )r@   r<   r2  r5  )
r®   r<   r@   r<   r¯   Útyper°   r   r2  r   )r®   r<   r@   r<   r³   r   r2  r5  )r@   r<   r2  r€   )r@   r<   r»   r€   r2  r5  )r@   r<   rÁ   r€   r2  r5  )r@   r<   r2  r   )r@   r<   r¡   r   r2  r5  )rr   )r@   r<   r   r<   rÌ   r   r2  rX   )r@   r<   r   r<   r2  r5  )r@   r<   r2  r<   )
r@   r<   r   r<   rÌ   r   r0   r1  r2  rX   )r@   r<   r   r<   rÌ   r   rö   r   r÷   r   rù   r   rû   r   r2  rX   )r@   r<   r2  r3  )r2  r€   )r@   r<   r2  z	List[str])r   r6  r2  rX   )&Ú__name__Ú
__module__Ú__qualname__Ú__doc__rF   rO   rY   rq   r‰   r’   r”   rš   r�   r¦   r¨   r±   r´   r¸   r¼   r¿   rÂ   rÆ   rÉ   rÍ   rÛ   rÝ   rë   rí   rõ   r	  r  r  r  r  r  r!  r$  r0  rÕ   r   r   r.   r.   J   s“  „ ÙOð RVñ)Øð)Ø.1ð)Ø?Nð)à	ó)óVKó87.ðr
Ø]aó
ð2 6:ÐZ^Ø!¨dÈØ'+ÈtØ&+ÈØ#'ÈDñQ!Ø$'ðQ!Ø;>ðQ!ØHKðQ!à&ðQ!à/2ðQ!àIWðQ!ð ðQ!ð ),ðQ!ð CFðQ!ð "%ð	Q!ð IMð	Q!ð
  $ðQ!ð
 AFðQ!ð !ðQ!ð =JðQ!ð VZóQ!ófEð NRðAØðAØ/4ðAØ=JðAØVZóAólóhópó:Lóó_ó\ógó
^óhó
bódôô$ó2"óOó4Jð EJÐimñEØðEØ'*ðEØ<AðEØWfðEà	óEð( EJØ$ÀSÐRVØ.2ÀÐcfñ+PØð+PØ'*ð+PØ<Að+Pàð+Pà=Bð+Pð ',ð+Pð \að+Pð 
ó	+PðZ `eõ .ó	!ó/óó@ó,2óJôBr   r.   )r   rX   r2  r6  )r$   r<   r%   r<   r&   r<   r   r<   r'   r   r    r   r2  zTuple[bool, Optional[str]])r<  Ú
__future__r   rg   ÚloggingrŒ   rR   Útypingr   r   r   r   r   Úhermes_state_commonr	   r
   rS   r   r   r   r   r   r   Ú	getLoggerrC   r™   r;   r  r   r,   r.   rÕ   r   r   ú<module>rB     sÚ   ðñCõ
 #ã Û Û Û ß 3Õ 3÷\÷ \ó \ð
 
ˆ×	Ñ	˜>Ó	*€ð fð ðñ -Ð-AÐCUÓVÐWð XÙ,Ð-AÐCUÓVÐWð X Ø 7Ð 0× 7Ñ 7¸'Ô BÐCð Dñ 0°Ó8Ð9ð :ð!€ó.mð
MØ9óM÷"C
Bò C
Br   