+
    lHàj•_  ã                   ó$  a € R8 tB0 t R t^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
t
^ RIt^ RIt^ RIHtHtHt ]P"                  ! ]4      tRtRt]P,                  P/                  ]
P0                  ! 4       R4      tRt^tRt]! 0 R9m4      tRtR	t ]PB                  ! R
4      t"^xt#]PH                  ! 4       t%]&! 4       t'] ^ k R t(R R lt)]PB                  ! R4      t*Rt+]PB                  ! R4      t,R R lt-R R lt.R R lt/R:R R llt0R R lt1R R lt2R R lt3R R  lt4R! R" lt5R# R$ lt6]3R% R& llt7R' R( lt8R) R* lt9R+ R, lt:]PB                  ! R-]Pv                  4      t<R. R/ lt=R]R3R0 R1 llt>R2 R3 lt?R4 R5 lt@R]3R6 R7 lltAR# );u  Tool result persistence -- preserves large outputs instead of truncating. Layers against
context overflow: (1) per-tool caps inside each tool; (2) ``maybe_persist_tool_result`` â€”
output over the tool's threshold is persisted and replaced by a preview + path; canonical home
is ALWAYS host-side ``$HERMES_HOME/cache/spillover/{id}.txt`` (works for sessions that never
ran a terminal), remote backends get the translated in-sandbox path (probed for readability)
else a copy in the sandbox temp dir; (3) ``enforce_turn_budget``.N)ÚDEFAULT_PREVIEW_SIZE_CHARSÚBudgetConfigÚDEFAULT_BUDGETz<persisted-output>z</persisted-output>zhermes-resultszcache/spilloverÚ__budget_enforcement__z<mcp-result-metadata>z</mcp-result-metadata>z[^A-Za-z0-9_.-]+c                 ó2   € ^ RI Hp  V ! 4       \        ,          # )z<Return $HERMES_HOME/cache/spillover as a Path (not created).©Úget_hermes_home)Úhermes_constantsr   ÚSPILLOVER_SUBDIRr   s    Ú>/home/ubuntu/.hermes/hermes-agent/tools/tool_result_storage.pyÚget_spillover_dirr   +   s   € å0ÙÓÔ/Õ/Ð/ó    c                ó$   € V ^8„  d   QhR\         /# ©é   Úreturn©Úint)Úformats   "r   Ú__annotate__r   1   s   € ÷ 8ñ 8¤Cñ 8r   c                 ó6  €  ^ RI Hp  \        V ! 4       P                  R4      ;'       g    / P                  R^Z4      4      p\        P
                  ! V4      '       g   \        #  \        \        \        T^,          4      4      #   \         d
    \        u # i ; i)aJ  Default spillover age = the session retention window (``sessions.retention_days``).
Spill files are archives the durable transcript points at, not a cache: a session resumed
days later must still find what the ``<persisted-output>`` pointer promises (#126351).
Falls back to the legacy 24h cache age when the config is unreadable.)Úload_config_readonlyÚsessionsÚretention_days)
Úhermes_cli.configr   ÚfloatÚgetÚmathÚisfiniteÚSPILLOVER_MAX_AGE_HOURSÚ	ExceptionÚmaxr   )r   Údayss     r   Ú_spillover_retention_hoursr#   1   sƒ   € ð
'Ý:ÜÑ*Ó,×0Ñ0°Ó<×BÐBÀ×GÑGÐHXÐZ\Ó]Ó^ˆÜ�}Š}˜T×"Ò"Ü*Ð*ð #ô Ô&¬¨D°2­I«Ó7Ð7øô ô 'Ü&Ò&ð'ús   ‚'B ª2B ÁB ÂBÂBz#spillover(?:/|\\+)([A-Za-z0-9_.-]+)zH(instr(content, 'spillover') > 0 OR instr(api_content, 'spillover') > 0)z4(?:^|[/\\])(?:spillover|hermes-results)[/\\][^/\\]+$c                ó0   € V ^8„  d   QhR\         R\        /# )r   Úpathr   )ÚstrÚdict)r   s   "r   r   r   P   s   € ÷ 	/ñ 	/¤ð 	/¬ñ 	/r   c                ót   € \        V \        4      '       d   \        P                  V 4      '       g   / # RRRR/# )z´Extra read_file not-found fields for a persisted-tool-result path: the archive was pruned,
so the model gets "expired" instead of a generic miss it might take for a typo (#126351).ÚexpiredTÚhintu  This was a persisted tool result archive and it has expired (pruned with its session or by the cache sweep); the full output is no longer recoverable. Inspect the current state before re-running the original tool â€” the call that produced it may already have taken effect.)Ú
isinstancer&   Ú_ARCHIVE_PATH_REÚsearch)r%   s   &r   Úexpired_archive_fieldsr.   P   s=   € ô �dœC× Ò Ô(8×(?Ñ(?À×(EÒ(EØˆ	Ø�t˜Vð-ð/ð /r   c                ó$   € V ^8„  d   QhR\         /# r   ©Úset)r   s   "r   r   r   \   s   € ÷ ñ ¤sñ r   c                 ó¶   € \        4       pV  FH  p\        V\        4      '       g   K  RV9   g   K$  VP                  \        P                  V4      4       KJ  	  V# )zVSpillover archive basenames referenced by transcript message text (empty set on none).Ú	spillover)r1   r+   r&   ÚupdateÚ_SPILLOVER_NAME_REÚfindall)ÚtextsÚnamesÚtexts   *  r   Úspillover_names_in_textr:   \   sF   € ä“€EÛˆÜ�dœC× Ô  [°DÖ%8Ø�L‰LÔ+×3Ñ3°DÓ9Ö:ñ ð €Lr   c                ó2   € V ^8„  d   QhR\         R,          /# ©r   r   Nr0   )r   s   "r   r   r   e   s   € ÷ ñ ¬S°4­Zñ r   c                ó&  € V P                   P                   R,          pVP                  4       '       g   \        4       #  \        P                  ! VP                  4        R2RRR7      p VP                  R\         R24      P                  4       pVP                  4        \        T4      R	8”  d   R# \        4       pT F  w  rVT\        YV4      ,          pK  	  T#   TP                  4        i ; i  \        P                  \        3 d     R# i ; i)
ue  Basenames under *spill_dir* still referenced by any message in the home's ``state.db``.

``set()`` when no database exists (no sessions â†’ nothing references anything), ``None``
when the reference set is UNKNOWN (unreadable / truncated query) so callers fail closed
and keep the files; a plain read-only connection is enough, the write path owns the locks.zstate.dbz?mode=roTg      @)ÚuriÚtimeoutz0SELECT content, api_content FROM messages WHERE z LIMIT 20001Ni N  )ÚparentÚexistsr1   Úsqlite3ÚconnectÚas_uriÚexecuteÚSPILLOVER_SQL_FILTERÚfetchallÚcloseÚErrorÚOSErrorÚlenr:   )Ú	spill_dirÚdb_pathÚconnÚrowsr8   ÚcontentÚapi_contents   &      r   Úreferenced_spillover_namesrR   e   sí   € ð ×Ñ×%Ñ%¨
Õ2€GØ�>‰>×ÒÜ‹uˆð
ä�Š '§.¡.Ó"2Ð!3°8Ð<À$ÐPSÔTˆð	Ø—<‘<ØBÔCWÐBXÐXdÐeóç‰h‹jð ð �J‰JŒLô ˆ4ƒy�5ÔÙÜ“€EÛ $ÑˆØÔ(¨Ó>Õ>Šñ !%à€Løð �J‰J�LûÜ�M‰Mœ7Ð#ô Úðús)   ¿*C1 Á*'C ÂC1 ÃC.Ã.C1 Ã1DÄDc                ó>   € V ^8„  d   QhR\         R,          R\         /# )r   Úmax_age_hoursNr   r   )r   s   "r   r   r   �   s   € ÷ "ñ "¬3°­:ð "Äñ "r   c                óz  € V f   \        4       MT p\        P                  ! 4       VR,          ,
          p. p \        \        4       P	                  4       4      pT FN  p TP                  4       '       d5   TP                  4       P                  T8  d   TP                  T4       KL  KN  KP  	  T'       g   ^ # \        \        4       4      p^ pT F4  pTe   TP                  T9   d   K   TP                  4        T^,          pK6  	  T#   \
         d     ^ # i ; i  \
         d     KÍ  i ; i  \
         d     Kl  i ; i)u�  Delete spillover files older than *max_age_hours*; returns count removed (same
contract as the ``cleanup_*_cache`` helpers the gateway housekeeping loop runs hourly).
A ``None`` age means the session retention window, not a cache TTL â€” an explicit
``max_age_hours`` (tests, legacy callers) still wins. An expired file is deleted only
when no message in the home's state.db references it: the transcript's
``<persisted-output>`` promise outlives the archive's mtime exactly as long as the
owning session does (#126351) â€” referenced archives leave with their session, via the
unlink SessionDB delete/prune performs, not with the age sweep.i  )r#   ÚtimeÚlistr   ÚiterdirrJ   Úis_fileÚstatÚst_mtimeÚappendrR   ÚnameÚunlink)rT   Ú	age_hoursÚcutoffr)   ÚentriesÚfÚ
referencedÚremoveds   &       r   Úcleanup_spillover_cachere   �   s  € ð 1>Ò0EÔ*Ô,È=€IÜ�YŠY‹[˜I¨Õ,Õ-€FØ€GðÜÔ(Ó*×2Ñ2Ó4Ó5ˆó ˆð	Ø�y‰y�{Š{˜qŸv™v›x×0Ñ0°6Ô9Ø—‘˜qÖ!ñ  :‰{ñ ÷ ÙÜ+Ô,=Ó,?Ó@€JØ€GÛˆØÒ §¡¨:Ô!5Ùð	Ø�H‰HŒJØ�q�LŠGñ ð €Nøô) ô Úðûô ô 	Úð	ûô ô 	Úð	ús6   ·!D ÁADÃ(D+ÄDÄDÄD(Ä'D(Ä+D:Ä9D:c                ó   € V ^8„  d   QhRR/# r<   © )r   s   "r   r   r   ¦   s   € ÷ 8ñ 8˜tñ 8r   c                 ó~  € ^ RI Hp  V ! 4       p\        ;_uu_ 4        V\        9   d    RRR4       R# \        P	                  V4       RRR4        \        4       ;p'       d   \        P                  RV4       R# R#   + '       g   i     L=; i  \         d"   p\        P                  RT4        Rp?R# Rp?ii ; i)zÓBest-effort prune, at most once per process PER PROFILE HOME (CLI-only installs never run
housekeeping; a multiplexed gateway must sweep every profile's ``cache/spillover``, not just the
first one that spilled).)Úhermes_home_keyNz#Pruned %d expired spillover file(s)zSpillover prune failed: %s)	r	   ri   Ú_spillover_prune_lockÚ_spillover_pruned_homesÚaddre   ÚloggerÚdebugr    )ri   Úhome_keyrd   Úexcs       r   Ú_prune_spillover_oncerq   ¦   s‘   € õ 1ÙÓ €Hß	Ö	ØÔ.Ô.Ø÷ 
Ñ	ô 	 ×#Ñ# HÔ-÷ 
ð8Ü-Ó/Ð/ˆ7Ö/Ü�L‰LÐ>ÀÖHñ 0÷ 
×	ûô ô 8Ü�‰Ð1°3×7Ò7ûð8ús(   œA=³A=Á(B Á=B	ÂB<ÂB7Â7B<c                ó$   € V ^8„  d   QhR\         /# r   )Úbool)r   s   "r   r   r   ·   s   € ÷ 	ñ 	œdñ 	r   c                óV   € V f   R#  ^ RI Hp \        W4      #   \         d     R# i ; i)zªTrue when this process should write the spill file directly: ``env=None`` (no sandbox
yet) or the local backend. Remote backends resolve ``read_file`` inside the sandbox.T)ÚLocalEnvironmentF)Útools.environments.localru   r+   r    )Úenvru   s   & r   Ú_is_host_side_envrx   ·   s1   € ð ‚{ÙðÝ=Ü˜#Ó0Ð0øÜô Úðús   ˆ ™(§(c                ó0   € V ^8„  d   QhR\         R\         /# )r   rP   Úfilename©r&   )r   s   "r   r   r   Ã   s   € ÷ ñ ¤ð ´ñ r   c                ó  € V P                  RRR7      p \        4       pVP                  RRR7       W1,          pVP                  V4       \        P
                  ! V4      P                  pT\        T4      8w  d4   \        P                  RY\        T4      4        TP                  4        R# \        4        \        T4      #   \         d"   p\        P                  RY4        Rp?R# Rp?ii ; i  \         d     R# i ; i)	a6  Write host-side to $HERMES_HOME/cache/spillover; returns path str or None.

The write is size-verified before the caller tells the model "Full output saved":
a partially-flushed file (quota, ENOSPC race) fails closed to the bounded inline
truncation instead of referencing an archive that silently lost bytes.
úutf-8Úreplace©ÚerrorsT)ÚparentsÚexist_okz!Spillover write failed for %s: %sNu]   Spillover write for %s is not lossless (%d bytes on disk, expected %d) â€” discarding archive)Úencoder   ÚmkdirÚwrite_bytesÚosrZ   Úst_sizerJ   rm   ÚwarningrK   r^   rq   r&   )rP   rz   ÚdatarL   r%   Úpersisted_sizerp   s   &&     r   Ú_write_to_spilloverr‹   Ã   sá   € ð �>‰>˜'¨)ˆ>Ó4€DðÜ%Ó'ˆ	Ø�‰ ¨tˆÔ4ØÕ#ˆØ×Ñ˜ÔÜŸš ›×.Ñ.ˆð œ˜T›Ô"Ü�‰ð2à¤c¨$£iô	
ð
	Ø�K‰KŒMñ ÜÔÜˆt‹9Ðøô ô Ü�‰Ð:¸HÔJÝûðûô ô 	ØÙð	ús*   •AC ÂC2 ÃC/ÃC*Ã*C/Ã2DÄ Dc                ó>   € V ^8„  d   QhR\         R\         R,          /# )r   Ú	host_pathr   Nr{   )r   s   "r   r   r   ã   s   € ÷ ñ ¬sð ¼CÀ$½Jñ r   c                ó
  €  ^ RI Hp V! V 4      p \        TRR4      ;pe   TP                  RR7        TP                  R\        P                  ! T4       2^R	7      P                  R
^4      ^ 8X  d   T#  R#   \         d"   p\        P	                  RT4        Rp?R# Rp?ii ; i  \         d!   p\        P	                  RT4        Rp?LšRp?ii ; i  \         d"   p\        P	                  RT4        Rp?R# Rp?ii ; i)u(  Path where a remote backend can read *host_path*, or None. Translates via the image
tools' helper, forces a sync for synced backends, then PROBES readability â€” a persistent
container created before spillover joined the mount list lacks the bind mount and must
fall back to the in-sandbox write.)Úto_agent_visible_cache_pathz%Spillover path translation failed: %sNÚ_sync_managerT)ÚforcezSpillover sync failed: %sztest -r ©r?   Ú
returncodez&Spillover readability probe failed: %s)Útools.credential_filesr�   r    rm   rn   ÚgetattrÚsyncrE   ÚshlexÚquoter   )r�   rw   r�   Úvisiblerp   Úsync_managers   &&    r   Ú_sandbox_visible_spillover_pathr›   ã   sø   € ð
ÝFÙ-¨iÓ8ˆð7Ü# C¨¸$Ó?Ð?ˆLÒLØ×Ñ DÐÔ)ðDØ�;‰;˜¤%§+¢+¨gÓ"6Ð!7Ð8À"ˆ;ÓE×IÑIÈ,ÐXYÓZÐ^_Ô_ØˆNð `ñ øô ô Ü�‰Ð<¸cÔBÝûðûô ô 7Ü�‰Ð0°#×6Ñ6ûð7ûô
 ô DÜ�‰Ð=¸s×CÐCÙûðDúsF   ‚A9 ‘#B( µA C Á9B%ÂB Â B%Â(CÂ3CÃCÃDÃ!C=Ã=Dc                ó$   € V ^8„  d   QhR\         /# r   r{   )r   s   "r   r   r   û   s   € ÷ 	Xñ 	X¤ñ 	Xr   c                ó  € \        V RR4      pRp\        V4      '       d	    V! 4       pV'       d   VP                  R4      ;'       g    R R2# \        #   \         d!   p\        P	                  RT4        Rp?LRRp?ii ; i)z=Return the best temp-backed storage dir for this environment.Úget_temp_dirNz"Could not resolve env temp dir: %sÚ/z/hermes-results)r•   Úcallabler    rm   rn   ÚrstripÚSTORAGE_DIR)rw   rž   Útemp_dirrp   s   &   r   Ú_resolve_storage_dirr¤   û   s|   € ä˜3 °Ó5€LØ€HÜ�×Òð	DÙ#“~ˆH÷ ?Gˆh�o‰o˜cÓ"×)Ð) cÐ*¨/Ð:ÐWÌKÐWøô ô 	DÜ�L‰LÐ=¸s×CÑCûð	Dús   ¢A ÁB Á A;Á;B c                ó0   € V ^8„  d   QhR\         R\         /# )r   Útool_use_idr   r{   )r   s   "r   r   r     s   € ÷ 
ñ 
¤sð 
¬sñ 
r   c                óž  € \        T ;'       g    R4      p\        P                  RV4      P                  R4      pW!8g  pT;'       g    RpV'       g   \	        V4      \
        8”  dd   \        P                  ! VP                  R4      4      P                  4       R,          pVR\
         P                  R4      ;'       g    RpV RV 2pV R2# )z3Return a single safe filename for a tool result id.Útool_resultÚ_z._-r}   :Né   NNz.txt)r&   Ú_UNSAFE_RESULT_FILENAME_CHARSÚsubÚstriprK   Ú_MAX_RESULT_FILENAME_STEMÚhashlibÚsha256rƒ   Ú	hexdigestr¡   )r¦   Úraw_idÚ	safe_stemÚchangedÚdigests   &    r   Ú_safe_result_filenamer¶     s¸   € ä�×-Ð- Ó.€FÜ-×1Ñ1°#°vÓ>×DÑDÀUÓK€IØÑ!€GØ×*Ð*˜]€Iß”#�i“.Ô#<Ô<Ü—’ §¡¨gÓ 6Ó7×AÑAÓCÀCÕHˆØÐ8Ô8Ð9×@Ñ@ÀÓG×XÐXÈ=ˆ	Ø �k  6 (Ð+ˆ	Øˆ[˜ÐÐr   c                ó^   € V ^8„  d   QhR\         R\        R\        \         \        3,          /# )r   rP   Ú	max_charsr   )r&   r   Útuplers   )r   s   "r   r   r     s3   € ÷ Rñ Rœcð R¬cð RÔSXÔY\Ô^bÐYbÕScñ Rr   c                ó�   € \        V 4      V8:  d   V R3# V P                  R^ V4      pT RW!^,          8”  d   V^,            R3# T R3# )zGTruncate at last newline within max_chars. Returns (preview, has_more).FÚ
NT)rK   Úrfind)rP   r¸   Úlast_nls   && r   Úgenerate_previewr¾     sW   € ä
ˆ7ƒ|�yÔ Ø˜ˆ~ÐØ�m‰m˜D ! YÓ/€GØÐJ 7¸!­^Ô#;�G˜a•KÐKÈTÐQÐQÀÐKÈTÐQÐQr   c                ó0   € V ^8„  d   QhR\         R\         /# )r   rP   r   r{   )r   s   "r   r   r     s   € ÷ &añ &aœCð &a¤Cñ &ar   c                óB  €  \         P                  ! V 4      p\	        T\
        4      '       d   T'       d   \        T4      \        8:  g   T # TP                  R4      p\	        T\        4      '       d	   T'       g   T # TP                  4        UUu/ uF  w  r4TR8w  g   K  Y4bK  	  pppT'       g   T#  \         P                  ! TR^R\        R7      pT R\         RT R\         R2#   \        \        3 d    T u # i ; iu uppi   \        \        3 d    Tu # i ; i)u�  Rewrite an MCP handler result envelope into the text it wraps, else return *content*.

``tools/mcp_tool_handlers.py::_render_call_tool_result`` hands the model a JSON string
(``{"result": <text>, ...}``) so structured metadata survives inline delivery. Persisting
that string verbatim put a multi-hundred-KB document on ONE line with escaped newlines, so
the ``read_file`` offset/limit pagination the ``<persisted-output>`` block recommends could
not be used at all (#90426).

Recognized by SHAPE, not by tool name: the envelope is the only JSON object in the codebase
whose keys are a subset of ``{"result", "structuredContent", "_meta"}`` with a non-empty
string ``result``. That keeps opaque JSON from any other tool verbatim, and it also covers
the aggregate path (``enforce_turn_budget`` persists under ``_BUDGET_TOOL_NAME``, so a
``mcp__``-prefix test would miss exactly the results it has to fix).

Sibling members are appended after the text in a delimited metadata block instead of being
dropped: they are the structured payloads ``_render_call_tool_result`` deliberately keeps
for the model (#115430), and the spill file is the only copy left once the envelope is
replaced by the preview. Anything unrecognized â€” unparseable JSON, a non-object, an unknown
key, a missing/empty/non-string ``result`` (e.g. a structuredContent-only result, which has
no pageable text) â€” is persisted verbatim, exactly as before.
ÚresultFT)Úensure_asciiÚindentÚ	sort_keysÚdefaultz

r»   )ÚjsonÚloadsÚ	TypeErrorÚ
ValueErrorr+   r'   r1   Ú_MCP_ENVELOPE_KEYSr   r&   ÚitemsÚdumpsÚ_ENVELOPE_METADATA_TAGÚ_ENVELOPE_METADATA_CLOSING_TAG)rP   Úpayloadr9   ÚkeyÚvalueÚextrasÚmetadatas   &      r   Ú_pageable_textrÔ     s  € ð,Ü—*’*˜WÓ%ˆô �gœt×$Ò$¯G¼3¸w»<ÔK]Ô;]ØˆØ�;‰;�xÓ €DÜ�dœC× Ò ¯ØˆØ+2¯=©=¬?ÔN©?™Z˜S¸cÀX¹oŒjˆcŠj©?€FÑNßØˆðÜ—:’:˜f°5ÀÈdÔ\_Ô`ˆð ˆV�4Ô.Ð/¨r°(°¸2Ô>\Ð=]Ð]_Ð`Ð`øô ”zÐ"ô ØŠðüó Oøô
 ”zÐ"ô ØŠðús/   ‚C) ÂDÂ DÂ4D Ã)C?Ã>C?ÄDÄDc                ó<   € V ^8„  d   QhR\         R\         R\        /# )r   rP   Úremote_pathr   )r&   rs   )r   s   "r   r   r   E  s!   € ÷ &ñ &œsð &´ð &¼dñ &r   c                ó²  € \         P                  P                  V4      p^ RIHp V! V4       R\
        P                  ! V4       2pVP                  V^V R7      P                  R^4      ^ 8w  d   R# \        V P                  RRR7      4      p VP                  R	\
        P                  ! V4       2^R
7      pTP                  R^4      ^ 8w  d   R# \        TP                  RR4      ;'       g    R4      P                  4       P!                  4       p	T	'       d   T	R,          P#                  4       '       g   R# \%        T	R,          4      p
Y¦8X  d   R# \        P'                  RYT4        TP                  R\
        P                  ! T4       2^R
7       R#   \         d"   p\        P                  RY4        Rp?R# Rp?ii ; i  \         d     R# i ; i)at  Write content into the sandbox via env.execute(); True on success. Content goes through
stdin, not the command string: Linux ``MAX_ARG_STRLEN`` caps one argv element at 128 KB,
so a heredoc-in-command silently failed for exactly the oversized results this handles.

The write is round-trip verified with ``wc -c`` (one extra exec RTT per oversized result):
a zero exit from ``cat`` does not prove the bytes landed (quota/ENOSPC races, API-body
truncation on payload backends). A measured mismatch removes the archive and fails closed;
an unprobeable backend (no ``wc``, exec error, unparseable output) stays best-effort success.)Ú_private_dirs_cmdz
 && cat > )r?   Ú
stdin_datar“   Fr}   r~   r   zwc -c < r’   z$Sandbox size probe failed for %s: %sNTÚoutputÚ u^   Sandbox spill for %s is not lossless (%d bytes in sandbox, expected %d) â€” discarding archivezrm -f éÿÿÿÿ)r†   r%   ÚdirnameÚtools.code_execution_rpcrØ   r—   r˜   rE   r   rK   rƒ   r    rm   rn   r&   r­   ÚsplitÚisdigitr   rˆ   )rP   rÖ   rw   Ústorage_dirrØ   ÚcmdÚexpectedÚproberp   ÚrawrŠ   s   &&&        r   Ú_write_to_sandboxræ   E  s”  € ô —'‘'—/‘/ +Ó.€Kõ ;Ù Ó,Ð-ð .Ü—{’{ ;Ó/Ð0ð2€Cà
‡{�{�3 ¨w€{Ó7×;Ñ;¸LÈ!ÓLÐPQÔQÙä�7—>‘> '°)�>Ó<Ó=€HðØ—‘˜h¤u§{¢{°;Ó'?Ð&@ÐAÈ2�ÓNˆð ‡y�y�˜qÓ! QÔ&ÙÜ
ˆe�i‰i˜ "Ó%×+Ð+¨Ó
,×
2Ñ
2Ó
4×
:Ñ
:Ó
<€Cß�c˜"•g—o‘o×'Ò'ÙÜ˜˜R�“\€NØÔ!ÙÜ
‡N�NÐsØ°ô:ðØ�‰�fœUŸ[š[¨Ó5Ð6Ð7ÀˆÔDñ øô# ô Ü�‰Ð;¸[ÔNÝûðûô ô ØÙðús*   Â*F Å,*G ÆGÆ#F?Æ?GÇGÇGc          
      óT   € V ^8„  d   QhR\         R\        R\        R\         R\         /# )r   ÚpreviewÚhas_moreÚoriginal_sizeÚ	file_pathr   )r&   rs   r   )r   s   "r   r   r   n  s1   € ÷ /ñ /¤cð /´Tð /Ì#ð /Ü(+ð/Ü03ñ/r   c                óÒ   € VR,          pVR8¼  d   VR,          R R2MVR R2p\          RVR RV RV R	\        V 4       R
2
V ,           V'       d   RMR,           R\         2,           # )z/Build the <persisted-output> replacement block.i   z.1fz MBz KBz!
This tool result was too large (Ú,z characters, z).
Full output saved to: uÃ  
Use the read_file tool with offset and limit to access specific sections of this output.
Recovery: page through the saved file with read_file (offset/limit) or process it with execute_code â€” do NOT re-request the same data from the remote API; the archive is kept while this session's transcript references it. If it is missing, inspect the current state before retrying â€” the call that produced it may already have taken effect.

Preview (first z	 chars):
z
...rÛ   r»   )ÚPERSISTED_OUTPUT_TAGrK   ÚPERSISTED_OUTPUT_CLOSING_TAG)rè   ré   rê   rë   Úsize_kbÚsize_strs   &&&&  r   Ú_build_persisted_messagerò   n  sž   € ð ˜dÕ"€GØ-4¸¬_�'˜D•. Ð% SÑ)ÀWÈSÀMÐQTÐBU€HäÐ
 ð !+Ø+8¸Ð*;¸=ÈÈ
ð S!Ø!* ð ,ô ˜g›,˜ zð		3ð õ
	÷ !)‘W¨bõ
	2ð Ô+Ð,Ð
-õ	.ð/r   z^Full output saved to: (.+)$c                ó>   € V ^8„  d   QhR\         R\         R,          /# )r   rP   r   Nr{   )r   s   "r   r   r   …  s   € ÷ 5ñ 5¤Cð 5¬C°$­Jñ 5r   c                óÄ   € \        V \        4      '       d!   \        V 9   d   \        P	                  V 4      MRpV'       d    VP                  ^4      P                  4       # R# )z²File path from a <persisted-output> block, or None (lets the result-reference stubbing
guard in agent/tool_guardrails.py carry the spillover path instead of leaving it dangling).N)r+   r&   rî   Ú_PERSISTED_PATH_REr-   Úgroupr­   )rP   Úmatchs   & r   Úextract_persisted_pathrø   …  sO   € ô ˜7¤C×(Ò(Ô-AÀWÔ-Lô  ×&Ñ& wÔ/ØRVð 
ç%*ˆ5�;‰;�q‹>×ÑÓ!Ð4°Ð4r   c                ón   € V ^8„  d   QhR\         R\         R\         R\        R\        R,          R\         /# )r   rP   Ú	tool_namer¦   ÚconfigÚ	thresholdNr   )r&   r   r   )r   s   "r   r   r   �  s=   € ÷ );ñ );¤sð );´sð );Ìð );Ü&2ð);ä).°­ð);äADñ);r   c                óÄ  aaaaa€ Vf   VP                  S4      pV\        R4      8X  g   \        V 4      V8:  d   V # \        V 4      o\	        S4      p\        SVP                  R7      w  ooRR VVVVV3R lllp\        SV4      p\        V4      p	V	'       d   Ve	   V! V4      # V	'       gS   V'       d   \        Wƒ4      MRp
V
e   V! V
RV R24      # \        V4       RV 2p \        SW³4      '       d	   V! V4      #  \        P                  R
S\        V 4      4       S R\        V 4      R R2#   \         d"   p\        P                  R	ST4        Rp?LYRp?ii ; i)z¾Layer 2: persist an oversized result, return preview + path. ``threshold`` overrides
``config.resolve_threshold(tool_name)``; falls back to inline truncation when no write
location succeeds.NÚinf)r¸   c                ó<   € V ^8„  d   QhR\         R\         R\         /# )r   r%   Úhost_suffixr   r{   )r   s   "r   r   Ú/maybe_persist_tool_result.<locals>.__annotate__�  s&   € ÷ Yñ Yœð Y¬3ð Y¼ñ Yr   c                 óv   <€ \         P                  R SS\        S4      W4       \        SS\        S4      V 4      # )z6Persisted large tool result: %s (%s, %d chars -> %s%s))rm   ÚinforK   rò   )r%   r   ré   Úpersisted_contentrè   rú   r¦   s   &&€€€€€r   Ú
_persistedÚ-maybe_persist_tool_result.<locals>._persisted�  s:   ø€ Ü�‰ÐLØ˜{¬CÐ0AÓ,BÀDô	Wä'¨°¼3Ð?PÓ;QÐSWÓXÐXr   z [host: Ú]rŸ   zSandbox write failed for %s: %szDInline-truncating large tool result: %s (%d chars, no sandbox write)z 

[Truncated: tool response was rí   z3 chars. Full output could not be saved to sandbox.])rÛ   )Úresolve_thresholdr   rK   rÔ   r¶   r¾   Úpreview_sizer‹   rx   r›   r¤   ræ   r    rm   rˆ   r  )rP   rú   r¦   rw   rû   rü   rz   r  r�   Ú	host_sider™   rÖ   rp   ré   r  rè   s   &ff&&&       @@@r   Úmaybe_persist_tool_resultr  �  sq  ü€ ð ÒØ×,Ñ,¨YÓ7ˆ	Ø”E˜%“LÔ ¤C¨£L°IÔ$=Øˆô ' wÓ/ÐÜ$ [Ó1€HÜ(Ð):Àf×FYÑFYÔZÑ€GˆX÷Yö Yô $Ð$5°xÓ@€IÜ! #Ó&€Iß�YÒ*Ù˜)Ó$Ð$ß÷ FOÔ1°)ÔAÐTXˆØÒÙ˜g¨°)°¸AÐ'>Ó?Ð?Ü-¨cÓ2Ð3°1°X°JÐ?ˆð	PÜ Ð!2°K×EÒEÙ! +Ó.Ð.ð Fô ‡K�KÐVØœ3˜w›<ô)àˆiÐ9¼#¸g»,ÀqÐ9Ið J:ð :ð ;øô	 ô 	PÜ�N‰NÐ<¸kÈ3×OÑOûð	Pús   Ã&D3 Ä3EÄ>EÅEc                ó$   € V ^8„  d   QhR\         /# r   r   )r   s   "r   r   r   ¹  s   € ÷ ñ ¤3ñ r   c                ó|   € \        V \        4      '       d   \        R V  4       4      # \        T ;'       g    R4      # )zÊCharacters of TEXT a tool message carries: a string's length, or the summed text parts of a multimodal
part list (image parts are governed by the vision embed budget, and a list's ``len`` counts parts).c              3   óÊ   "  € T FY  p\        V\        4      '       g   K  VP                  R 4      R8X  g   K3  \        VP                  R4      ;'       g    R4      x € K[  	  R# 5i)Útyper9   rÛ   N)r+   r'   r   rK   )Ú.0Úps   & r   Ú	<genexpr>Ú%_content_text_size.<locals>.<genexpr>½  sL   é € Ðp±W°Ä
È1Ìd×@SÔ+ÐXY×X]ÑX]Ð^dÓXeÐioÑXoÔ+”3�q—u‘u˜V“}×*Ð*¨×+Ð+³Wùs   ‚A#ŸA#·A#ÁA#rÛ   )r+   rW   ÚsumrK   )rP   s   &r   Ú_content_text_sizer  ¹  s3   € ô �'œ4× Ò ÜÑp±WÓpÓpÐpÜˆw�}ˆ}˜"ÓÐr   c          
      ój   € V ^8„  d   QhR\         R\        R\        R\        \         \        3,          /# )r   Úpartsr¦   rû   r   )rW   r&   r   r¹   r   )r   s   "r   r   r   Á  s;   € ÷ oñ o¤Dð o´sð oÌð oÔZ_Ô`dÔfiÐ`iÕZjñ or   c           	     ó$  € \        V 4       UUu. uFz  w  rE\        V\        4      '       g   K  VP                  R4      R8X  g   K5  \        VP                  R4      \        4      '       g   K\  \
        VR,          9  g   Kp  WER,          3NK|  	  pppV'       g   V ^ 3# \        VR R7      w  rx\        V\        V RV 2W#^ R7      p	W˜8X  d   V ^ 3# . V RV O/ W,          CRV	/CNW^,           R O\        V4      \        V	4      ,
          3# u uppi )z_Persist the largest non-persisted text part of a multimodal list; ``(new parts, chars saved)``.r  r9   c                 ó&   € \        V ^,          4      # ©é   )rK   )Úts   &r   Ú<lambda>Ú*_spill_largest_text_part.<locals>.<lambda>Ç  s   € ¬¨Q¨q­T¬r   )rÐ   Ú_part©rP   rú   r¦   rw   rû   rü   N)
Ú	enumerater+   r'   r   r&   rî   r!   r  Ú_BUDGET_TOOL_NAMErK   )
r  r¦   rw   rû   Úir  r7   Úidxr9   Úreplacements
   &&&&      r   Ú_spill_largest_text_partr&  Á  s  € ä(1°%Ô(8ô [Ñ(8¡ ¼JÀqÌ$×<OŒ^ÐTU×TYÑTYÐZ`ÓTaÐekÑTkŒ^Ü˜AŸE™E &›M¬3×/ô Ü4HÐPQÐRXÕPYÑ4Yô ˆa�6•‹^Ñ(8€Eñ [çØ�aˆxˆÜ�EÑ2Ô3�I€CÜ+°DÔDUØ;F¸-ÀuÈSÈEÐ8RÐX[Ðvwôy€KàÔØ�aˆxˆØPˆU�4�Cˆ[ÐPÐ=˜U�ZÐ=¨°Ñ=ÐPÀÈAÅgÀhÀÐPÔRUÐVZÓR[Ô^aÐbmÓ^nÕRnÐnÐnùó[s   �D®DÁ"DÁ-DÂDc                óh   € V ^8„  d   QhR\         \        ,          R\        R\         \        ,          /# )r   Útool_messagesrû   r   )rW   r'   r   )r   s   "r   r   r   Ï  s+   € ÷  ñ  ¤t¬D¥zð  Ü ,ð ÜBFÄtÅ*ñ r   c           
     óˆ  € V  Uu. uF  p\        VP                  RR4      4      NK   	  pp\        V4      p\        V4       UUu. uFV  w  rg\	        W,          P                  R4      \
        4      '       g$   \        W,          P                  RR4      9  g   KS  Wg3NKX  	  pppWRP                  8:  d   V # \        VR RR7       Fï  w  r—WRP                  8:  d    V # W	,          R,          p
W	,          P                  RRV	 24      p\	        V
\
        4      '       dB   \        W«W4      w  rÍV'       d*   W],          pWÀV	,          R&   \        P                  RW½4       K™  \        V
\        VW^ R	7      pWê8w  g   Kµ  V\        V4      V,
          ,          pWàV	,          R&   \        P                  R
W·4       Kñ  	  V # u upi u uppi )a  Layer 3: persist the largest non-persisted results first until the turn's aggregate is
under budget. Mutates the list in-place and returns it. A multimodal result (part list) counts its
text characters and spills its largest text part; its images stay inline.rP   rÛ   c                 ó   € V ^,          # r  rg   )Úxs   &r   r  Ú%enforce_turn_budget.<locals>.<lambda>Û  s   € °a¸¶dr   T)rÐ   ÚreverseÚtool_call_idÚbudget_zFBudget enforcement: persisted a text part of tool result %s (%d chars)r   z7Budget enforcement: persisted tool result %s (%d chars))r  r   r  r!  r+   rW   rî   Úturn_budgetÚsortedr&  rm   r  r  r"  rK   )r(  rw   rû   ÚmsgÚsizesÚ
total_sizer#  ÚsizeÚ
candidatesr$  rP   r¦   r  Úsavedr%  s   &&&            r   Úenforce_turn_budgetr8  Ï  s©  € ñ
 DQÓQÁ=¸CÔ §¡¨	°2Ó 6Ö7Á=€EÐQÜ�U“€JÜ+4°UÔ+;ô VÑ+;¡ Ü Õ 0× 4Ñ 4°YÓ ?Ä×FÒFÜ)°Õ1A×1EÑ1EÀiÐQSÓ1TÑTô �1“)Ñ+;€Jñ Vð ×'Ñ'Ô'ØÐÜ˜J©NÀD×I‰	ˆØ×+Ñ+Ô+Øð$ Ðð#  Õ$ YÕ/ˆØ#Õ(×,Ñ,¨^¸wÀsÀe¸_ÓMˆÜ�gœt×$Ò$Ü3°GÈ#ÓV‰LˆEßØÕ#�
Ø05˜cÕ" 9Ñ-Ü—‘ÐdÐfqÔyÙÜ/ØÔ'8ÀkØ¨aô1ˆð Ö!Øœ#˜kÓ*¨TÕ1Õ1ˆJØ,7˜#Õ˜yÑ)Ü�K‰KÐQØ#ö+ñ% Jð( Ðùò7 RùóVs   …$F9ÁAF>ÂF>c                ó@   € V ^8„  d   Qh/ ^ \         9   d
   \        ;R&   # )r   rk   )Ú__conditional_annotations__r1   )r   s   "r   r   r      s#   € ÷ Eñ E÷N %Ò $œÑ $òOEr   >   Ú_metarÁ   ÚstructuredContent)N)Cr:  Ú__doc__r¯   rÆ   Úloggingr   r†   Úrer—   rB   ÚtempfileÚ	threadingrV   Útools.budget_configr   r   r   Ú	getLoggerÚ__name__rm   rî   rï   r%   ÚjoinÚ
gettempdirr¢   r
   r   r"  Ú	frozensetrÊ   rÍ   rÎ   Úcompiler«   r®   ÚLockrj   r1   rk   r   r#   r5   rF   r,   r.   r:   rR   re   rq   rx   r‹   r›   r¤   r¶   r¾   rÔ   ræ   rò   Ú	MULTILINErõ   rø   r  r  r&  r8  r   )r:  s   @r   Ú<module>rK     sŸ  øðöEó Û Û Û Û 	Û 	Û Û Û Û Û ç XÑ Xà	×	Ò	˜8Ó	$€Ø+Ð Ø4Ð Ø�g‰g�l‰l˜8×.Ò.Ó0Ð2BÓC€Ø$Ð ð Ð Ø,Ð ñ ÒGÓHÐ Ø0Ð Ø!9Ð Ø "§
¢
Ð+>Ó ?Ð ØÐ à!ŸšÓ(Ð Ù"›uÐ Ó $ò0õ8ð. —Z’ZÐ FÓGÐ àaÐ ð —:’:ÐUÓVÐ õ	/õõ÷8"õJ8õ"	õõ@õ0	Xõ
ð 5O÷ Rõ&aõR&õR/ð( —Z’ZÐ ?ÀÇÁÓNÐ õ5ð SWØ5CØ8<÷);õXõoð 8<Ø/=÷ ñ  r   