Ë
    ãß²j  ã                  óÌ   — d Z ddlm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 ddlmZmZ  ej                  e«      ZdZdZdZd	Zdd
„Zdd„Zddddœ	 	 	 	 	 	 	 	 	 dd„Zg d¢Zy)a   Spill oversized hook-injected context to disk with a preview placeholder.

Hook ``{"context": ...}`` output rides EVERY subsequent API call, so a large blob
inflates every turn and breaks the prompt-cache prefix. Above
``hooks.output_spill.max_chars`` (default 10000) the text is written under
``hooks.output_spill.directory`` (default ``<HERMES_HOME>/hook_outputs/<session>``)
and the payload becomes a ``preview_head``/``preview_tail`` excerpt plus the path.
``enabled: false`` disables. Never raises: an I/O failure still returns a preview.
é    )ÚannotationsN)ÚPath)ÚAnyÚDictÚOptional)Ú_coerce_intÚ_coerce_positive_inti'  iô  Tc                 óT  — i } 	 ddl m}  |«       xs i }t        |t        «      r|j	                  d«      nd}t        |t        «      r$t        |j	                  d«      t        «      r|d   } | j	                  dt        «      }| j	                  d«      }|�t        |«      nt        t        | j	                  d«      t        «      t        | j	                  d	«      t        d«      t        | j	                  d
«      t        d«      t        |t        «      r|dœS ddœS # t
        $ r i } Y Œºw xY w)z7Return resolved hook output-spill config. Never raises.r   )Úload_configÚhooksNÚoutput_spillÚenabledÚ	directoryÚ	max_charsÚpreview_headÚpreview_tail)r   r   r   r   r   )Úhermes_cli.configr   Ú
isinstanceÚdictÚgetÚ	ExceptionÚDEFAULT_ENABLEDÚboolr	   ÚDEFAULT_MAX_CHARSr   ÚDEFAULT_PREVIEW_HEADÚDEFAULT_PREVIEW_TAILÚstr)Úsectionr   Úcfgr   Úenabled_rawr   s         ú</home/ubuntu/.hermes/hermes-agent/tools/hook_output_spill.pyÚget_spill_configr"      s  € à €GðÝ1Ù‹mÒ!˜rˆÜ$.¨s´DÔ$9�—‘˜Ô ¸tˆÜ�eœTÔ"¤z°%·)±)¸NÓ2KÌTÔ'RØ˜NÑ+ˆGð —+‘+˜i¬Ó9€KØ—‘˜KÓ(€Ià(3Ð(?”4˜Ô$Ä_Ü)¨'¯+©+°kÓ*BÔDUÓVä# G§K¡K°Ó$?ÔAUÐWXÓYÜ# G§K¡K°Ó$?ÔAUÐWXÓYÜ",¨Y¼Ô"<�Yñð ð CGñð øô	 ò ØŠðús   „A(D ÄD'Ä&D'c                ó   — | r)t        t        j                  j                  | «      «      }nddlm} t         |«       «      dz  }|xs dj                  dd«      j                  dd«      j                  dd«      }||z  S )	zQPer-session spill directory; session id is sanitised so it can't escape ``base``.r   )Úget_hermes_homeÚhook_outputsz
no-sessionú/Ú_ú\z..)r   ÚosÚpathÚ
expanduserÚhermes_constantsr$   Úreplace)Údirectory_overrideÚ
session_idÚbaser$   Úsession_segments        r!   Ú_resolve_spill_dirr2   5   ss   € áÜ”B—G‘G×&Ñ&Ð'9Ó:Ó;‰å4Ü‘OÓ%Ó&¨Ñ7ˆØ!Ò1 \×:Ñ:¸3ÀÓD×LÑLÈTÐSVÓW×_Ñ_Ð`dÐfiÓj€OØ�/Ñ!Ð!ó    Úhook)r/   ÚsourceÚconfigc               ó¸  — | €yt        | t        «      s	 t        | «      } |�|n	t        «       }|j	                  dd«      s| S t        | «      t        |j	                  d«      xs t        «      k  r| S t        |j	                  d«      xs d«      }t        |j	                  d«      xs d«      }d}	 t        |j	                  d	«      |«      }dd
l	m
}	m}
  |	|d¬«       |t        j                  «       j                  › d�z  } |
|| j                  d«      r| n| dz   d¬«       t        |«      }t        | «      }d|› d|d›d�|rd|› d�ndz   g}|dkD  r| d| r|j%                  d| d| g«       |dkD  r||kD  r|j%                  d| | d g«       dj'                  |«      S # t        $ r Y yw xY w# t        $ r }t         j#                  d|«       Y d}~Œ¦d}~ww xY w)a&  Spill ``text`` to disk if it exceeds the configured cap.

    Returns ``text`` unchanged (under cap, disabled, or empty) or a preview
    string pointing at the full content. Non-string input is ``str()``-coerced;
    ``source`` labels the preview header; ``config`` overrides config.yaml.
    NÚ r   Tr   r   r   r   r   )Úensure_spill_dirÚwrite_text_exclusive)Úprivatez.txtú
zhook output spill failed: %sú[u    output truncated â€” ú,z chars; full content z	saved to ú]u#   unavailable â€” spill write failed]z--- head ---z--- tail ---)r   r   r   r"   r   ÚlenÚintr   r2   Útools.spill_safetyr9   r:   ÚuuidÚuuid4ÚhexÚendswithÚloggerÚwarningÚextendÚjoin)Útextr/   r5   r6   r   ÚheadÚtailÚ
saved_pathÚ	spill_dirr9   r:   Ú
spill_pathÚexcÚtotalÚpartss                  r!   Úspill_if_oversizedrT   @   sè  € ð €|ØÜ�dœCÔ ð	Ü�t“9ˆDð Ð&‰&Ô,<Ó,>€CØ�7‰7�9˜dÔ#ØˆÜ
ˆ4ƒy”C˜Ÿ™ Ó,ÒAÔ0AÓBÒBØˆÜˆs�w‰w�~Ó&Ò+¨!Ó,€DÜˆs�w‰w�~Ó&Ò+¨!Ó,€Dð !%€Jð<Ü& s§w¡w¨{Ó';¸ZÓHˆ	ßMñ 	˜¨DÕ1Ø¤D§J¡J£L×$4Ñ$4Ð#5°TÐ!:Ñ:ˆ
á˜Z°·±¸tÔ1D©È$ÐQUÉ+Ð_cÕdÜ˜“_ˆ
ô �‹I€Eà
ˆFˆ8Ð)¨%°¨Ð2GÐHÙ(2ˆY�z�l !Ñ$Ð8]ñ	_ð€Eð ˆa‚x�D˜˜$‘KØ�‰�n d¨5¨D kÐ2Ô3Øˆa‚x�E˜D’LØ�‰�n d¨D¨5¨6 lÐ3Ô4Ø�9‰9�UÓÐøôG ò 	Ùð	ûô. ò <Ü�‰Ð5°s×;Ñ;ûð<ús*   •F! Â1A=F0 Æ!	F-Æ,F-Æ0	GÆ9GÇG)r   r   r   r   r"   rT   )ÚreturnzDict[str, Any])r.   úOptional[str]r/   rV   rU   r   )
rK   r   r/   rV   r5   r   r6   zOptional[Dict[str, Any]]rU   r   )Ú__doc__Ú
__future__r   Úloggingr)   rC   Úpathlibr   Útypingr   r   r   Útools.tool_output_limitsr   r	   Ú	getLoggerÚ__name__rG   r   r   r   r   r"   r2   rT   Ú__all__© r3   r!   ú<module>ra      s˜   ðñõ #ã Û 	Û Ý ß &Ñ &ç Fà	ˆ×	Ñ	˜8Ó	$€ð Ð ØÐ ØÐ Ø€óó."ð /3À&Ðmqñ1Ø
ð1Ø+ð1Ø<?ð1ØRjð1àó1òh5�r3   