§
    øžyjÇP  ã                  óö  — 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 ddl	m
Z
 ddlmZ dZ G d„ d	e¦  «        Z G d
„ de¦  «        Z G d„ de¦  «        Z G d„ de¦  «        Z G d„ de¦  «        Z G d„ de¦  «        Ze G d„ d¦  «        ¦   «         Ze G d„ d¦  «        ¦   «         Z ej        d¦  «        Zddœd=d!„Zd>d$„Zd?d'„Zd@d)„ZdAd+„ZdBd-„ZdCd1„ZdDd3„Z dEd5„Z!	 dFdGd6„Z"	 dFdHd:„Z#dId;„Z$ddœdJd<„Z%dS )KuŒ  Single resolver for every media source -> bytes + mime.

All source handling (data:/http(s)/file/local/container) funnels through
:func:`resolve_image_source` so size and magic-byte checks are enforced exactly
once.  Returns raw bytes (not a path): the downstream step is base64 -> data URL
(RFC 2397) and provider base64 content blocks.

Images are the default and the historical purpose. Callers whose argument
takes video opt in via ``permitted=("video",)`` â€” the same confinement and
credential-guard pipeline applies, and only the type check at the end differs
(extension-table typing plus an mp4 magic sniff, rather than image magic
bytes). Every existing call site keeps the image-only default unchanged.

Security (terminal-backend confinement, GHSA-gpxw-6wxv-w3qq): under a non-local
terminal backend the file tools are confined to the sandbox (SECURITY.md 2.2),
but vision read images host-side. This resolver enforces the same boundary:

  * local backend            -> read any host path (chosen posture, unchanged)
  * non-local backend:
      path in a media cache   -> host-read (the gateway/download caches live on
                                 the host and are bind-mounted into the sandbox)
      path anywhere else      -> read the bytes *inside the sandbox* via exec-read
                                 (the agent can already ``cat`` any container file;
                                 this stays within the sandbox boundary and never
                                 reaches the host's ``/etc/passwd`` / ``~/.ssh``).

So a prompt-injected ``vision_analyze('/etc/passwd')`` under Docker reads the
*container's* file (what every other tool sees), not the host's â€” no escape â€”
while container-only images (tmpfs ``/workspace``, root-owned) are still
deliverable. This is the unified delivery + confinement model: the same
mechanism that fixes "vision can't see container files" also closes the escape.
é    )ÚannotationsN)Ú	dataclass)ÚPath)ÚOptionali   c                  ó(   ‡ — e Zd Zdddœdˆ fd„Zˆ xZS )	ÚImageResolutionErrorÚ ©ÚsrcÚoriginÚmessageÚstrr   r   c               óh   •— t          ¦   «                              |¦  «         ||c| _        | _        d S ©N)ÚsuperÚ__init__r   r   )Úselfr   r   r   Ú	__class__s       €ú8/home/ragecks/.hermes/hermes-agent/tools/image_source.pyr   zImageResolutionError.__init__5   s/   ø€ Ý‰Œ×Ò˜Ñ!Ô!Ð!Ø # VÐˆŒ�$”+�+�+ó    )r   r   r   r   r   r   )Ú__name__Ú
__module__Ú__qualname__r   Ú__classcell__)r   s   @r   r   r   4   sL   ø€ € € € € Ø35ÀRð ,ð ,ð ,ð ,ð ,ð ,ð ,ð ,ð ,ð ,ð ,ð ,r   r   c                  ó   — e Zd ZdS )ÚUnsupportedSchemeN©r   r   r   © r   r   r   r   :   ó   € € € € € Ø€Dr   r   c                  ó   — e Zd ZdS )ÚSourceUnsafeNr   r   r   r   r!   r!   >   r   r   r!   c                  ó   — e Zd ZdS )ÚSourceTooLargeNr   r   r   r   r#   r#   B   r   r   r#   c                  ó   — e Zd ZdS )ÚSourceNotFoundNr   r   r   r   r%   r%   F   r   r   r%   c                  ó   — e Zd ZdS )Ú
NotAnImageNr   r   r   r   r'   r'   J   r   r   r'   c                  ó   — e Zd ZU dZded<   dS )ÚResolveContextNúOptional[str]Útask_id)r   r   r   r+   Ú__annotations__r   r   r   r)   r)   N   s#   € € € € € € à!€GÐ!Ð!Ð!Ñ!Ð!Ð!r   r)   c                  ó.   — e Zd ZU ded<   ded<   ded<   dS )ÚResolvedImageÚbytesÚdatar   Úmimer   N)r   r   r   r,   r   r   r   r.   r.   S   s+   € € € € € € à€K€K�KØ€I€I�IØ€K€K�K€K€Kr   r.   z^[A-Za-z][A-Za-z0-9+.\-]*://©Úimage©Ú	permittedr   r   Úctxr5   ÚtupleÚreturnc             ƒ  ó\  K  — t          | t          ¦  «        r|                      ¦   «         st          dt          | ¦  «        ¬¦  «        ‚|                      ¦   «         }|                     d¦  «        r%t          |¦  «        \  }}t          ||d||¦  «        S |                     d¦  «        rHt          |¦  «        }|rt          ||¬¦  «        ‚t          t          |¦  «        ƒ d {V —†dd||¦  «        S t                               |¦  «        r8|                     ¦   «                              d¦  «        st          d	|¬¦  «        ‚|                     ¦   «                              d¦  «        r|t          d¦  «        d …         n|}t          t           j                             |¦  «        ¦  «        }t'          ||¦  «        }	|	�­|	                     ¦   «         r™	 d
dlm}
 n# t.          $ r d }
Y nw xY w|
�K	  |
t          |	¦  «        ¦  «         n1# t0          $ r$}t          t          |¦  «        |d¬¦  «        ‚d }~ww xY wt3          j        |	j        ¦  «        ƒ d {V —†}t          |dd||¦  «        S t9          ¦   «         rt          d|› d�|d¬¦  «        ‚t;          ||||¦  «        ƒ d {V —†S )Nzimage_url is required©r   údata:r0   )úhttp://úhttps://r	   Úhttpzfile://zgUnrecognized image source scheme. Use an http(s) URL, a local file path, a file:// URI, or a data: URL.r   )Úraise_if_read_blockedÚfiler
   zmedia file not found: 'ú')Ú
isinstancer   Ústripr%   Ú
startswithÚ_resolve_data_urlÚ	_finalizeÚ_http_block_reasonr!   Ú_download_to_bytesÚ
_SCHEME_REÚmatchÚlowerr   Úlenr   ÚosÚpathÚ
expanduserÚ_permitted_host_read_targetÚis_fileÚagent.file_safetyr?   Ú	ExceptionÚ
ValueErrorÚasyncioÚ	to_threadÚ
read_bytesÚ_is_local_terminal_backendÚ_resolve_container_fallback)r   r6   r5   Úsr0   r1   ÚreasonÚ	candidateÚpÚhost_targetr?   Úexcs               r   Úresolve_image_sourcer`   _   s  è è € õ �c�3ÑÔð D s§y¢y¡{¤{ð DÝÐ4½#¸c¹(¼(ÐCÑCÔCÐCØ�	Š	‰Œ€AØ‡|‚|�GÑÔð ;Ý& qÑ)Ô)‰
ˆˆdÝ˜˜t V¨Q°	Ñ:Ô:Ð:Ø‡|‚|Ð+Ñ,Ô,ð PÝ# AÑ&Ô&ˆØð 	.Ý˜v¨1Ð-Ñ-Ô-Ð-ÝÕ1°!Ñ4Ô4Ð4Ð4Ð4Ð4Ð4Ð4°b¸&À!ÀYÑOÔOÐOå×Ò˜ÑÔð 
 1§7¢7¡9¤9×#7Ò#7¸	Ñ#BÔ#Bð 
Ýð8àð
ñ 
ô 
ð 	
ð '(§g¢g¡i¤i×&:Ò&:¸9Ñ&EÔ&EÐL�•#�i‘.”.�/�/Ô"Ð"È1€IÝ�RŒW×Ò 	Ñ*Ô*Ñ+Ô+€Aõ .¨a°Ñ5Ô5€KØÐ ;×#6Ò#6Ñ#8Ô#8Ðð	)Ø?Ð?Ð?Ð?Ð?Ð?Ð?øÝð 	)ð 	)ð 	)Ø$(Ð!Ð!Ð!ð	)øøøà Ð,ðCØ%Ð%¥c¨+Ñ&6Ô&6Ñ7Ô7Ð7Ð7øÝð Cð Cð CÝ"¥3 s¡8¤8°¸6ÐBÑBÔBÐBøøøøðCøøøåÔ& {Ô'=Ñ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>ˆÝ˜˜r 6¨1¨iÑ8Ô8Ð8Ý!Ñ#Ô#ð Sõ Ð;°qÐ;Ð;Ð;ÀÈ6ÐRÑRÔRÐRõ -¨Q°°Q¸	ÑBÔBÐBÐBÐBÐBÐBÐBÐBs*   ÇG! Ç!G0Ç/G0Ç6H È
H=ÈH8È8H=rZ   útuple[bytes, str]c                óú  — |                       d¦  «        \  }}}d|vrt          d| d d…         ¬¦  «        ‚|t          d¦  «        d …                              dd¦  «        d	                              ¦   «         pd
}t          |¦  «        dz  dz  t
          k    rt          d| d d…         ¬¦  «        ‚	 t          j        |d¬¦  «        }n.# t          $ r!}t          d|› �| d d…         ¬¦  «        ‚d }~ww xY w||fS )NÚ,z;base64z data: URL must be base64-encodedé@   r:   r;   ú;é   r   úapplication/octet-streamé   é   zdata: URL exceeds size limitT©Úvalidatezinvalid base64 in data: URL: )
Ú	partitionr'   rL   ÚsplitrC   Ú_MAX_INGEST_BYTESr#   Úbase64Ú	b64decoderS   )rZ   ÚheaderÚ_ÚpayloadÚdeclaredr0   r_   s          r   rE   rE   Ÿ   s"  € ØŸš SÑ)Ô)Ñ€FˆAˆwØ˜ÐÐÝÐ;ÀÀ3ÀBÀ3ÄÐHÑHÔHÐHØ•c˜'‘l”l�m�mÔ$×*Ò*¨3°Ñ2Ô2°1Ô5×;Ò;Ñ=Ô=Ð[ÐA[€HåˆG‰Œ�qÑ˜QÑÕ!2Ò2Ð2ÝÐ;ÀÀ3ÀBÀ3ÄÐHÑHÔHÐHðLÝÔ °$Ð7Ñ7Ô7ˆˆøÝð Lð Lð LÝÐ>¸Ð>Ð>ÀAÀcÀrÀcÄFÐKÑKÔKÐKøøøøðLøøøà�ˆ>Ðs   Â4C Ã
C6ÃC1Ã1C6Úurlr*   c                ó€   — ddl m} ddlm}  || ¦  «        sdS  || ¦  «        }|r|                     d¦  «        pdS dS )u	  Return a human-readable block reason, or None when the URL is allowed.

    Pre-flight short-circuit: policy-blocked URLs are refused BEFORE any
    network I/O. ``_download_image`` re-checks policy internally (per attempt
    and against the final redirect target) â€” that second evaluation is
    intentional, not redundant: this one guarantees no bytes move for a
    blocked URL; the inner one covers redirects and non-resolver callers.
    Preserves the specific website-policy message so the agent sees *why*.
    r   )Úis_safe_url)Úcheck_website_accesszblocked: unsafe or private URLr   zblocked by website policyN)Útools.url_safetyrw   Útools.website_policyrx   Úget)ru   rw   rx   Úblockeds       r   rG   rG   ®   sv   € ð -Ð,Ð,Ð,Ð,Ð,Ø9Ð9Ð9Ð9Ð9Ð9àˆ;�sÑÔð 0Ø/Ð/Ø"Ð" 3Ñ'Ô'€GØð EØ�{Š{˜9Ñ%Ô%ÐDÐ)DÐDØˆ4r   r/   c              ƒ  óÊ  K  — dd l }ddlm} |                     dd¬¦  «        5 }t	          |j        ¦  «        }d d d ¦  «         n# 1 swxY w Y   	  || |¦  «        ƒ d {V —† t          j        |j        ¦  «        ƒ d {V —†	 | 	                    d¬¦  «         S # t          $ r$}t          t          |¦  «        | d¬	¦  «        ‚d }~ww xY w# | 	                    d¬¦  «         w xY w)
Nr   )Ú_download_imagez.imgF)ÚsuffixÚdeleteT)Ú
missing_okr>   r
   )ÚtempfileÚtools.vision_toolsr~   ÚNamedTemporaryFiler   ÚnamerU   rV   rW   ÚunlinkÚPermissionErrorr!   r   )ru   r‚   r~   ÚtfÚtmpr_   s         r   rH   rH   Ã   sY  è è € Ø€O€O€Oà2Ð2Ð2Ð2Ð2Ð2à	×	$Ò	$¨F¸5Ð	$Ñ	AÔ	Að ÀRÝ�2”7‰mŒmˆðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð$àˆo˜c 3Ñ'Ô'Ð'Ð'Ð'Ð'Ð'Ð'Ð'ÝÔ& s¤~Ñ6Ô6Ð6Ð6Ð6Ð6Ð6Ð6Ð6ð 	�
Š
˜dˆ
Ñ#Ô#Ð#Ð#øõ ð =ð =ð =Ý�3˜s™8œ8¨°VÐ<Ñ<Ô<Ð<øøøøð=øøøøð 	�
Š
˜dˆ
Ñ#Ô#Ð#Ð#øøøs5   ¤AÁA	ÁA	Á0B Â
CÂ#CÃCÃC
 Ã
C"Úboolc                 óx   — t          j        dd¦  «                             ¦   «                              ¦   «         dv S )zºTrue when the terminal backend runs directly on the host.

    Mirrors ``tools.browser_tool._is_local_backend`` and terminal_tool's own
    dispatch, which key off ``TERMINAL_ENV``.
    ÚTERMINAL_ENVÚlocal)r�   r	   )rM   ÚgetenvrC   rK   r   r   r   rX   rX   Ô   s3   € õ Œ9�^ WÑ-Ô-×3Ò3Ñ5Ô5×;Ò;Ñ=Ô=ÀÐNÐNr   Úlistc                 ó^   — ddl m}   | ¦   «         }|dz  |dz  |dz  |dz  |dz  |dz  |d	z  gS )
a-  Agent-managed media cache directories under HERMES_HOME (host side).

    The only host paths vision may read under a non-local backend: gateway-
    downloaded inbound media and the tools' own URL-download temp dirs. Covers
    the consolidated ``cache/`` layout and the legacy flat directories.
    r   )Úget_hermes_homeÚcacheÚimagesÚimage_cacheÚaudio_cacheÚvideo_cacheÚtemp_vision_imagesÚtemp_video_files)Úhermes_constantsr‘   )r‘   Úhomes     r   Ú_media_cache_rootsr›   Ý   se   € ð 1Ð0Ð0Ð0Ð0Ð0àˆ?ÑÔ€Dàˆw‰Øˆx‰Øˆ}ÑØˆ}ÑØˆ}ÑØÐ#Ñ#ØÐ!Ñ!ðð r   r]   r   úOptional[Path]c                ó¬  — t          ¦   «         r'	 |                      ¦   «         S # t          $ r | cY S w xY wddlm} t           |t          | ¦  «        ¦  «        ¦  «        }	 |                     ¦   «         }n# t          $ r Y dS w xY wt          ¦   «         D ]=}	 |                     |                     ¦   «         ¦  «         |c S # t          $ r Y Œ:w xY wdS )a  Return the host path to read, or ``None`` if a host read is not permitted.

    - Local backend: any path is permitted (chosen posture). Returns ``p``.
    - Non-local backend: permitted only if the path resolves inside a media
      cache root. A container-visible cache path (e.g. ``/root/.hermes/cache/
      images/x.png``) is first translated back to its host mount; anything that
      is not under a cache returns ``None`` so the caller routes it to the
      in-sandbox exec-read instead of reading the host filesystem.
    r   )Úfrom_agent_visible_cache_pathN)
rX   ÚresolverS   Útools.credential_filesrž   r   r   r›   Úrelative_torT   )r]   r6   rž   Úhost_candidateÚrealÚroots         r   rP   rP   ò   s  € õ "Ñ#Ô#ð ð	Ø—9’9‘;”;ÐøÝð 	ð 	ð 	ØˆHˆHˆHð	øøøð EÐDÐDÐDÐDÐDåÐ7Ð7½¸A¹¼Ñ?Ô?Ñ@Ô@€NðØ×%Ò%Ñ'Ô'ˆˆøÝð ð ð Øˆtˆtðøøøå"Ñ$Ô$ð ð ˆð	Ø×Ò˜TŸ\š\™^œ^Ñ,Ô,Ð,ØˆKˆKˆKøÝð 	ð 	ð 	ØˆHð	øøøàˆ4s0   �$ ¤3²3Á"A7 Á7
BÂBÂ(CÃ
CÃCr+   c                óP   — | sd S 	 ddl m}  || ¦  «        S # t          $ r Y d S w xY w)Nr   )Úget_active_env)Útools.terminal_toolr¦   rS   )r+   r¦   s     r   Ú_get_active_envr¨     sX   € Øð ØˆtðØ6Ð6Ð6Ð6Ð6Ð6àˆ~˜gÑ&Ô&Ð&øÝð ð ð Øˆtˆtðøøøs   † —
%¤%ÚNonec                óT   — | sdS 	 ddl m}  || ¦  «         dS # t          $ r Y dS w xY w)uÜ  Lazily bring up the sandbox (SSH/Docker/â€¦) before an in-sandbox read.

    Unlike the terminal tool, vision never triggered environment creation, so a
    session whose first action is ``vision_analyze`` on a container-only path
    under a non-local backend found no active env and failed â€” until a terminal
    command happened to create one (issue #62825). Best-effort: any failure just
    leaves the env absent and the caller hits the existing fail-closed error.
    Nr   )Úensure_task_env)r§   r«   rS   )r+   r«   s     r   Ú_ensure_container_envr¬     s`   € ð ð ØˆðØ7Ð7Ð7Ð7Ð7Ð7àˆ˜Ñ Ô Ð Ð Ð øÝð ð ð Øˆˆðøøøs   † ™
'¦'c              ƒ  ó(  K  — ddl }ddl}t          |j        ¦  «         t	          |j        ¦  «        }|€t          d| › d�|d¬¦  «        ‚|                     t          | ¦  «        ¦  «        }dt          dz   › d	|› d
�}dddœ}	t          d¦  «        D ]V}
 |j
        |j        |¦  «        ƒ d{V —†}	|	                     dd¦  «        dk    r n|
dk    r |j        d¦  «        ƒ d{V —† ŒW|	                     dd¦  «        dk    r|	                     d¦  «        pd                     ¦   «                              ¦   «         }t!          d„ |D ¦   «         d¦  «        }|rd|dd…         › d�nd}t          d| › d|› �|d¬¦  «        ‚	 t#          j        |	                     dd¦  «        d¬¦  «        }n)# t&          $ r}t)          d| › d|› �|¬¦  «        ‚d}~ww xY wt+          |¦  «        t          k    rt-          d|d¬¦  «        ‚t/          |dd||¦  «        S )a"  Read the image bytes inside the sandbox (fail-closed when none exists).

    Reached when a host read is not permitted or the host file is absent. The
    agent can already ``cat`` any container file (file_operations.py reads
    root-owned mode-600 files this way), so this stays within the same sandbox
    boundary and never touches the host filesystem. ``--`` stops a leading-dash
    path from being parsed as a ``base64`` option; ``base64 -w0`` is GNU-only,
    so pipe through ``tr -d`` for BusyBox.

    Fail-closed: if there is no active sandbox env we refuse rather than falling
    back to a host read, so a non-cache host path under a sandbox never leaks.

    Cold-start retry: under Docker the very first exec against a freshly
    started container can fail (empty pipe / partial setup) while an identical
    second call succeeds. We retry once with a short delay before giving up,
    so callers don't see "could not read inside the sandbox" on a file that is
    verifiably readable on the immediate retry. See #76566.

    Diagnostic: when every attempt fails, the container's own output (stderr
    + stdout) is folded into the raised error so the user can distinguish
    "no such file" from "permission denied" from "container never came up"
    instead of staring at one opaque message.
    r   NrA   z[' is not reachable inside the sandbox and no active sandbox session is available to read itÚ	containerr
   zhead -c rf   z < z | base64 | tr -d '\n'r	   )Ú
returncodeÚoutputé   r¯   g333333Ã?r°   c              3  óf   K  — | ],}|                      ¦   «         ¯|                      ¦   «         V — Œ-d S r   )rC   )Ú.0Úlns     r   ú	<genexpr>z._resolve_container_fallback.<locals>.<genexpr>r  s7   è è € Ð>Ð> R°2·8²8±:´:Ð>�b—h’h‘j”jÐ>Ð>Ð>Ð>Ð>Ð>r   z (éÈ   ú)zcould not read 'z' inside the sandboxTrj   z%sandbox returned non-image data for 'z': r:   úmedia exceeds size limit)rU   Úshlexr¬   r+   r¨   r%   Úquoter   rn   ÚrangerV   Úexecuter{   ÚsleeprC   Ú
splitlinesÚnextro   rp   rS   r'   rL   r#   rF   )r]   r6   r   r5   rU   r¹   ÚenvÚqpÚcmdÚlast_resÚattemptÚdiagÚfirstr   r0   r_   s                   r   rY   rY   0  s«  è è € ð4 €N€N€NØ€L€L€Lõ
 ˜#œ+Ñ&Ô&Ð&å
˜#œ+Ñ
&Ô
&€CØ
€{Ýð/�ð /ð /ð /à˜Kð)ñ )ô )ð 	)ð 
�Š•S˜‘V”VÑ	Ô	€BØ
JÕ&¨Ñ*Ð
JÐ
J¨rÐ
JÐ
JÐ
J€Cà$%°Ð4Ð4€HÝ˜‘8”8ð &ð &ˆØ*˜Ô*¨3¬;¸Ñ<Ô<Ð<Ð<Ð<Ð<Ð<Ð<ˆØ�<Š<˜ aÑ(Ô(¨AÒ-Ð-ØˆEØ�aŠ<ˆ<ð  �'”- Ñ%Ô%Ð%Ð%Ð%Ð%Ð%Ð%Ð%øØ‡|‚|�L !Ñ$Ô$¨Ò)Ð)Ø—’˜XÑ&Ô&Ð,¨"×3Ò3Ñ5Ô5×@Ò@ÑBÔBˆõ Ð>Ð>¨4Ð>Ñ>Ô>ÀÑCÔCˆØ(-Ð5Ð$�e˜D˜S˜D”kÐ$Ð$Ð$Ð$°2ˆÝØ>˜qÐ>Ð>°fÐ>Ð>Ø˜Kð)ñ )ô )ð 	)ðWÝÔ §¢¨X°rÑ :Ô :ÀTÐJÑJÔJˆˆøÝð Wð Wð WÝÐLÀÐLÐLÀsÐLÐLÐRUÐVÑVÔVÐVøøøøðWøøøå
ˆ4�y„yÕ$Ò$Ð$ÝÐ7¸SÈÐUÑUÔUÐUÝ�T˜2˜{¨C°Ñ;Ô;Ð;s   Æ*F. Æ.
GÆ8GÇGr0   Údeclared_mimer   c                óÌ  — ddl m} t          | ¦  «        t          k    rt	          d||¬¦  «        ‚ || ¦  «        }|�(d|vrt          d||¬¦  «        ‚t          | ||¬¦  «        S d|v r0d	| dd
…                              ¦   «         v rt          | d|¬¦  «        S d|v r6t          | |¦  «        }|�t          | ||¬¦  «        S t          d||¬¦  «        ‚t          d||¬¦  «        ‚)u¿  Intrinsic-correctness chokepoint: ingest byte cap + type check.

    The cap here is the generous 50MB *ingest* budget, not the 20MB provider
    payload cap â€” a 20-50MB image must survive this step so the call site can
    resize it under the payload cap. See ``_MAX_INGEST_BYTES``.

    Images are typed by magic bytes. Video (opt-in via ``permitted``) is typed
    by the extension table plus an mp4 container sniff: extension typing is
    sufficient because every downstream consumer re-validates â€” the upload
    gateway signs the content type into its presigned URL and the vendor
    rejects undecodable input â€” so a wrong guess is a clean rejection there
    rather than a hole here.
    r   )Ú"_detect_image_mime_type_from_bytesr¸   r
   Nr3   z3source is an image, but this argument takes a video)r0   r1   r   s   <svgi   zimage/svg+xmlÚvideoz/source is not a recognized video (mp4 expected)z source is not a recognized image)	rƒ   rÉ   rL   rn   r#   r'   r.   rK   Ú_detect_video_mime)r0   rÇ   r   r   r5   rÉ   ÚsniffedÚ
video_mimes           r   rF   rF   €  s0  € ð  FÐEÐEÐEÐEÐEå
ˆ4�y„yÕ$Ò$Ð$ÝÐ7¸SÈÐPÑPÔPÐPà0Ð0°Ñ6Ô6€GØÐØ˜)Ð#Ð#ÝÐRÐX[ÐdjÐkÑkÔkÐkÝ $¨W¸VÐDÑDÔDÐDà�)ÐÐ ¨4°°°¬;×+<Ò+<Ñ+>Ô+>Ð >Ð >õ  $¨_ÀVÐLÑLÔLÐLà�)ÐÐÝ'¨¨cÑ2Ô2ˆ
ØÐ!Ý  d°ÀFÐKÑKÔKÐKÝÐJÐPSÐ\bÐcÑcÔcÐcå
Ð7¸SÈÐ
PÑ
PÔ
PÐPr   c                óô   — ddl m} ddlm} t                               |¦  «        r ||¦  «        j        n|} |t          |¦  «        ¦  «        }|�|S t          | ¦  «        dk    r| dd…         dk    rd	S dS )
zÜVideo MIME from the extension table, else the mp4/mov container magic.

    The magic fallback covers extensionless sources (data: URLs, URLs with
    query strings): ISO base-media files carry ``ftyp`` at offset 4.
    r   )Úurlsplit)Ú_detect_video_mime_typeNé   ri   é   s   ftypz	video/mp4)	Úurllib.parserÏ   rƒ   rÐ   rI   rJ   rN   r   rL   )r0   r   rÏ   rÐ   Ú	path_partÚby_extensions         r   rË   rË   ª  s�   € ð &Ð%Ð%Ð%Ð%Ð%à:Ð:Ð:Ð:Ð:Ð:å&0×&6Ò&6°sÑ&;Ô&;ÐD��˜‘”Ô"Ð"À€IØ*Ð*­4°	©?¬?Ñ;Ô;€LØÐØÐÝ
ˆ4�y„y�2‚~€~˜$˜q ˜sœ) wÒ.Ð.Øˆ{Øˆ4r   c             ƒ  óN  K  — | pd                      ¦   «         }|r'|                     ¦   «                              d¦  «        r| S t          |t	          |¬¦  «        |¬¦  «        ƒ d{V —†}t          j        |j        ¦  «                             d¦  «        }|j	        pd}d|› d	|› �S )
ue  Convert a path-like media source into a ``data:`` URL via the resolver.

    Generation tools (image_generate / video_generate) forward model-supplied
    source images to provider plugins, which historically read local paths off
    the HOST filesystem regardless of terminal backend. Under a non-local
    backend that is both broken (the file usually lives in the sandbox, so the
    host read misses) and inconsistent with the confinement model vision/video
    analysis enforce (GHSA-gpxw-6wxv-w3qq): the sandbox boundary should govern
    every model-supplied path.

    This helper is the dispatch-layer chokepoint: URL-shaped sources
    (http/https/data) pass through untouched; anything path-like resolves
    through :func:`resolve_image_source` â€” media-cache host reads, bounded
    in-sandbox exec-read, lazy env bring-up, credential guard, ingest cap â€”
    and comes back as a ``data:`` URL every provider already accepts.

    Callers apply this only under a non-local terminal backend: on the local
    backend providers keep their existing host-side reads (chosen posture,
    zero behavior change).
    r	   )r<   r=   r;   )r+   r4   NÚasciirg   r;   z;base64,)
rC   rK   rD   r`   r)   ro   Ú	b64encoder0   Údecoder1   )r   r+   r5   rZ   ÚresolvedÚencodedr1   s          r   Ú resolve_local_source_to_data_urlrÜ   ½  sÑ   è è € ð. 
ˆ�×ÒÑÔ€AØð �—’‘	”	×$Ò$Ð%EÑFÔFð Øˆ
Ý)Ø	�> 'Ð*Ñ*Ô*°iðñ ô ð ð ð ð ð ð €Hõ Ô˜xœ}Ñ-Ô-×4Ò4°WÑ=Ô=€GØŒ=Ð6Ð6€DØ*�4Ð*Ð* Ð*Ð*Ð*r   )r   r   r6   r)   r5   r7   r8   r.   )rZ   r   r8   ra   )ru   r   r8   r*   )ru   r   r8   r/   )r8   rŠ   )r8   r�   )r]   r   r6   r)   r8   rœ   )r+   r*   )r+   r*   r8   r©   )r2   )
r]   r   r6   r)   r   r   r5   r7   r8   r.   )r0   r/   rÇ   r   r   r   r   r   r5   r7   r8   r.   )r0   r/   r   r   r8   r*   )r   r   r+   r*   r5   r7   r8   r   )&Ú__doc__Ú
__future__r   rU   ro   rM   ÚreÚdataclassesr   Úpathlibr   Útypingr   rn   rS   r   r   r!   r#   r%   r'   r)   r.   ÚcompilerI   r`   rE   rG   rH   rX   r›   rP   r¨   r¬   rY   rF   rË   rÜ   r   r   r   ú<module>rä      s`  ððð ð@ #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø 	€	€	€	Ø 	€	€	€	Ø !Ð !Ð !Ð !Ð !Ð !Ø Ð Ð Ð Ð Ð Ø Ð Ð Ð Ð Ð ð %Ð ð,ð ,ð ,ð ,ð ,˜9ñ ,ô ,ð ,ð	ð 	ð 	ð 	ð 	Ð,ñ 	ô 	ð 	ð	ð 	ð 	ð 	ð 	Ð'ñ 	ô 	ð 	ð	ð 	ð 	ð 	ð 	Ð)ñ 	ô 	ð 	ð	ð 	ð 	ð 	ð 	Ð)ñ 	ô 	ð 	ð	ð 	ð 	ð 	ð 	Ð%ñ 	ô 	ð 	ð ð"ð "ð "ð "ð "ñ "ô "ñ „ð"ð ðð ð ð ð ñ ô ñ „ðð ˆRŒZÐ7Ñ8Ô8€
ð "ð	=Cð =Cð =Cð =Cð =Cð =Cð@ð ð ð ðð ð ð ð*$ð $ð $ð $ð"Oð Oð Oð Oðð ð ð ð*ð ð ð ð@ð ð ð ðð ð ð ð( @JðM<ð M<ð M<ð M<ð M<ðb PZð'Qð 'Qð 'Qð 'Qð 'QðTð ð ð ð( =Gð+ð +ð +ð +ð +ð +ð +ð +r   