Ë
    áß²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 h d£ZdZdd	„Zdd
„Zdd„Zdd„Zddddœ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd„Zdd„Zy)a|  ``$HERMES_HOME/cache/<kind>/`` materialisation helpers for the image/video
generation provider ABCs.

Several backends return *ephemeral* delivery URLs that expire before a downstream
consumer (Telegram ``send_photo``, browser fetch) can resolve them, so providers
materialise the bytes locally at tool-completion time. Filenames are
``<prefix>_<YYYYMMDD_HHMMSS>_<uuid8>.<ext>``.
é    )ÚannotationsN)ÚPath)ÚDictÚOptionalÚTuple)Úurljoin>   é-  é.  é/  é3  é4  é   c                óR   — ddl m}  |«       dz  | z  }|j                  dd¬«       |S )zBReturn ``$HERMES_HOME/cache/<kind>/``, creating parents as needed.r   )Úget_hermes_homeÚcacheT)ÚparentsÚexist_ok)Úhermes_constantsr   Úmkdir)Úkindr   Úpaths      ú9/home/ubuntu/.hermes/hermes-agent/agent/provider_media.pyÚ	cache_dirr      s,   € å0ÙÓ˜wÑ&¨Ñ-€DØ‡J�J�t d€JÔ+Ø€Kó    c                óÐ   — t         j                   j                  «       j                  d«      }t        j                  «       j
                  d d }t        | «      |› d|› d|› d|› �z  S )Nz%Y%m%d_%H%M%Sé   Ú_ú.)ÚdatetimeÚnowÚstrftimeÚuuidÚuuid4Úhexr   )r   ÚprefixÚ	extensionÚtsÚshorts        r   Ú
cache_pathr)      s_   € Ü	×	Ñ	×	Ñ	Ó	 ×	)Ñ	)¨/Ó	:€BÜ�J‰J‹L×Ñ˜R˜aÐ €EÜ�T‹? ˜x q¨¨¨A¨e¨W°A°i°[ÐAÑAÐAr   c               óB   — t        | ||«      }|j                  |«       |S )z:Write raw bytes to the cache and return the absolute path.)r)   Úwrite_bytes)r   Úrawr%   r&   r   s        r   Ú
save_bytesr-   %   s#   € ä�d˜F IÓ.€DØ×Ñ�SÔØ€Kr   c               óF   — t        | t        j                  |«      ||¬«      S )z?Decode base64 data into the cache and return the absolute path.)r%   r&   )r-   Úbase64Ú	b64decode)r   Úb64_datar%   r&   s       r   Úsave_b64r2   ,   s   € ä�dœF×,Ñ,¨XÓ6¸vÐQZÔ[Ð[r   F)ÚheadersÚrequire_known_content_typeÚtrusted_originc               óê  ‡— ddl }ddlm}m}m} |||}}}t        t        dz   «      D �]‚  }|r, ||«      rt        |	› d|› �«      ‚|j                  |d¬«      }n" ||«      st        |	› d|› �«      ‚ ||d¬«      }|5  |j                  d	||¬
«      5 }|j                  t        v rO|j                  j                  d«      }|st        |	› d|› �«      ‚t        ||«      dd}}}	 ddd«       ddd«       ŒÍ|j                  s |j!                  «        |j#                  «        |j                  j                  d«      xs dj%                  dd«      d   j'                  «       j)                  «       }|j                  |«      }|r|€t        |	› d|xs d› �«      ‚|€8|j%                  dd«      d   j)                  «       Št+        ˆfd„|D «       |«      }t-        | ||«      }d}|j/                  d«      5 }|j1                  |¬«      D ][  }|sŒ|t3        |«      z  }||kD  r2|j5                  «        t7        |«       t        |	› d|› d|dz  › d�«      ‚|j9                  |«       Œ] 	 ddd«       |dk(  r&t7        |«       t        |
j;                  |¬«      «      ‚|cddd«       cddd«       c S  t        |	› dt        › d|› �«      ‚# 1 sw Y   ŒbxY w# 1 sw Y   nxY w	 ddd«       �ŒÀ# 1 sw Y   �ŒÊxY w)uy  Stream-download *url* into the cache with a size cap.

    The extension comes from the response ``Content-Type`` (an explicit table â€”
    never inherit a type pointing at HTML/JSON from a degenerate response), then
    the URL suffix (some CDNs return ``application/octet-stream``), then
    *default_extension*. Raises on any network / HTTP / oversize / empty error so
    callers can fall back to the bare URL; a partial file is never left behind.

    The URL is provider-supplied, so every hop is validated with
    ``tools.url_safety`` before a socket opens (and again at TCP connect by the
    guarded transport, closing DNS-rebinding TOCTOU). Caller-supplied *headers*
    (e.g. provider auth) go to the first hop only â€” a redirect target never
    receives them.

    *trusted_origin* is for callers that built *url* from the operator's own
    provider ``base_url`` (not from a provider response): the first hop skips the
    private-address class check so a LAN/loopback relay works without
    ``security.allow_private_urls``, but the cloud-metadata floor still applies and
    every redirect target is re-validated in full.
    r   N)Úcreate_ssrf_safe_clientÚis_always_blocked_urlÚis_safe_urlé   z( URL targets an always-blocked address: F)ÚtimeoutÚfollow_redirectsz# URL failed the SSRF safety check: ÚGET)r3   Úlocationz) download redirected without a Location: zContent-TypeÚ ú;z+ download returned unexpected Content-Type z	(missing)ú?c              3  óZ   •K  — | ]"  }‰j                  d |› �«      sŒ|dk(  rdn|–— Œ$ y­w)r   ÚjpegÚjpgN)Úendswith)Ú.0ÚextÚurl_paths     €r   ú	<genexpr>zsave_url.<locals>.<genexpr>n   s4   øè ø€ Òs¸SÐV^×VgÑVgÐjkÐloÐkpÐhqÕVr #¨¢-™°SÓ8Ñsùs   ƒ+�+Úwb)Ú
chunk_sizez at z	 exceeds i   zMB cap; refusing to cache.)Úurlz download exceeded z redirects: )ÚhttpxÚtools.url_safetyr7   r8   r9   ÚrangeÚ_MAX_SAVE_URL_REDIRECTSÚ
ValueErrorÚClientÚstreamÚstatus_codeÚ_REDIRECT_STATUS_CODESr3   Úgetr   Ú
is_successÚreadÚraise_for_statusÚsplitÚstripÚlowerÚnextr)   ÚopenÚ
iter_bytesÚlenÚcloseÚ_unlink_quietÚwriteÚformat) r   rL   r%   r;   Ú	max_bytesrK   Úcontent_typesÚurl_extensionsÚdefault_extensionÚlabelÚempty_errorr3   r4   r5   rM   r7   r8   r9   Úcurrent_urlÚhop_headersÚtrusted_hopr   ÚclientÚresponser>   Úcontent_typer&   r   Úbytes_writtenÚfhÚchunkrH   s                                   @r   Úsave_urlrt   1   s:  ø€ ó4 ç\Ñ\à,/°¸.˜k�€KÜÔ*¨QÑ.Ó/ó 4ˆÙÙ$ [Ô1Ü  E 7Ð*RÐS^ÐR_Ð!`ÓaÐaØ—\‘\¨'ÀE�\ÓJ‰Fá˜{Ô+Ü  E 7Ð*MÈkÈ]Ð![Ó\Ð\Ù,°WÈuÔUˆFØñ +	Ø—‘˜u k¸;�ÓGð *È8Ø×'Ñ'Ô+AÑAØ'×/Ñ/×3Ñ3°JÓ?�HÙ#Ü(¨E¨7Ð2[Ð\gÐ[hÐ)iÓjÐjÜ<CÀKÐQYÓ<ZÐ\`Ðbg¨k �KØ÷*÷+	ð +	ð  ×*Ò*Ø—M‘M”OØ×-Ñ-Ô/à (× 0Ñ 0× 4Ñ 4°^Ó DÒ JÈ×QÑQÐRUÐWXÓYÐZ[Ñ\×bÑbÓd×jÑjÓl�Ø)×-Ñ-¨lÓ;�	Ù-°)Ð2CÜ$Ø ˜'Ð!LÈ\ÒMhÐ]hÐLiÐjóð ð Ð$Ø*×0Ñ0°°aÓ8¸Ñ;×AÑAÓC�HÜ $ÛsÀNÔsØ)ó!�Iô " $¨°	Ó:�Ø !�Ø—Y‘Y˜t“_ð (¨Ø!)×!4Ñ!4À
Ð!4Ó!Kò 
(˜Ù$Ø$Ø%¬¨U«Ñ3˜Ø(¨9Ò4ØŸH™HœJÜ)¨$Ô/Ü",Ø#( '¨¨c¨U°)¸IÈ+Ñ<VÐ;WÐWqÐ ró#ð ð Ÿ™ �ñ
(÷(ð ! AÒ%Ü! $Ô'Ü$ [×%7Ñ%7¸CÐ%7Ó%@ÓAÐAà÷U*ð *÷+	ó +	ð4ôj ˜�wÐ1Ô2IÐ1JÈ,ÐWZÐV[Ð\Ó
]Ð]÷%(ð (ú÷3*ð *úð *÷+	÷ +	ó +	úsK   Á>K(ÂAKÃ$K(Ã5C=KÇ2A1K	É$4KÊ	K(ËKË
KËKËK(Ë(K2	c                óD   — 	 | j                  «        y # t        $ r Y y w xY w)N)ÚunlinkÚOSError)r   s    r   rb   rb   ˆ   s"   € ðØ�‰�øÜò Ùðús   ‚ “	ž)r   ÚstrÚreturnr   )r   rx   r%   rx   r&   rx   ry   r   )
r   rx   r,   Úbytesr%   rx   r&   rx   ry   r   )
r   rx   r1   rx   r%   rx   r&   rx   ry   r   )r   rx   rL   rx   r%   rx   r;   Úfloatre   ÚintrK   r|   rf   zDict[str, str]rg   zTuple[str, ...]rh   rx   ri   rx   rj   rx   r3   zOptional[Dict[str, str]]r4   Úboolr5   r}   ry   r   )r   r   ry   ÚNone)Ú__doc__Ú
__future__r   r/   r   r"   Úpathlibr   Útypingr   r   r   Úurllib.parser   rU   rP   r   r)   r-   r2   rt   rb   © r   r   ú<module>r…      s  ðñõ #ã Û Û Ý ß (Ñ (Ý  â2Ð ØÐ óóBóó\ð GKØ',ÀUñ	T^Ø
ðT^ØðT^Ø$'ðT^Ø27ðT^ØDGðT^ØUXðT^à!ðT^à3BðT^àWZðT^ð ðT^ð !ðT^ð ,DðT^ð !%ð	T^ð ?Cð	T^ð
 
óT^ônr   