
    Fijm                    l    d Z ddlmZ ddlmZmZmZmZ ddlm	Z	 ddZ
dd
ZddZ G d d          ZdS )u  Shared FAL.ai SDK plumbing.

Holds the stateless atoms that every FAL-backed tool needs:

* :func:`import_fal_client` — lazy import + ``lazy_deps`` integration so
  ``fal_client`` isn't pulled at cold start (it added ~64 ms per CLI
  invocation when imported eagerly).
* :class:`_ManagedFalSyncClient` — wrapper that drives a Nous-managed
  fal-queue gateway through the standard ``fal_client.SyncClient``
  primitives.
* :func:`_normalize_fal_queue_url_format`, :func:`_extract_http_status`
  — small helpers used by both the managed client wrapper and
  ``_submit_fal_request``.

Stateful pieces (cache globals, ``_managed_fal_client*`` selectors,
``_submit_fal_request``) intentionally stay on
:mod:`tools.image_generation_tool`. That module is the patch target for
existing test suites (``tests/tools/test_image_generation.py``,
``tests/tools/test_managed_media_gateways.py``) and for the
``plugins/image_gen/fal/`` plugin's ``_it`` indirection — moving the
caches here would silently defeat ``monkeypatch.setattr(image_tool,
"_managed_fal_client", None)`` because the lookups would go against
``fal_common``'s namespace instead. See the per-rule walkthrough at
issue #26241 for details.
    )annotations)AnyDictOptionalUnion)	urlencodereturnr   c                     	 ddl m}   | dd           n9# t          $ r Y n-t          $ r!}t          t	          |                    d}~ww xY wddl}|S )u  Import ``fal_client`` (via ``lazy_deps`` when available) and return
    the module reference.

    Callers are responsible for caching the result on their own module
    global — keeping per-module globals lets tests monkey-patch the
    target module's ``fal_client`` attribute and have the patched value
    stick for that module's call sites.

    Raises :class:`ImportError` if the package is genuinely unavailable.
    r   )ensurez	image.falF)promptN)tools.lazy_depsr   ImportError	Exceptionstr
fal_client)_lazy_ensureexcr   s      5/home/ubuntu/.hermes/hermes-agent/tools/fal_common.pyimport_fal_clientr   !   s    $::::::[/////    $ $ $#c((###$s    
A	AAAqueue_run_originr   c                    t          | pd                                                              d          }|st          d          | dS )N /z$Managed FAL queue origin is required)r   striprstrip
ValueError)r   normalized_origins     r   _normalize_fal_queue_url_formatr   7   sW    ,23399;;BB3GG A?@@@""""    r   BaseExceptionOptional[int]c                    t          | dd          }|(t          |dd          }t          |t                    r|S t          | dd          }t          |t                    r|S dS )u   Return an HTTP status code from httpx/fal exceptions, else None.

    Defensive across exception shapes — httpx.HTTPStatusError exposes
    ``.response.status_code`` while fal_client wrappers may expose
    ``.status_code`` directly.
    responseNstatus_code)getattr
isinstanceint)r   r#   statuss      r   _extract_http_statusr)   >   sp     sJ--H=$77fc"" 	MS-..F&# 4r   c                  2    e Zd ZdZddZdd	d	d	d	d	d
ddZd	S )_ManagedFalSyncClientas  Small per-instance wrapper around ``fal_client.SyncClient`` for
    managed queue hosts.

    The wrapper carries its own ``fal_client`` module reference instead
    of reaching into a module global, so callers stay in control of
    which module's ``fal_client`` is in scope (matters for the test
    patches that swap the legacy module's ``fal_client`` attribute).
    r   r   keyr   r   c                  t          |dd           }|t          d          t          |dd           }|t          d          t          |          | _         ||          | _        t          | j        dd           | _        t          |dd           | _        t          |dd           | _        t          |d	d           | _        t          |d
d           | _	        t          |dd           | _
        t          |dd           | _        | j        t          d          | j        | j        t          d          | j        t          d          d S )N
SyncClientz>fal_client.SyncClient is required for managed FAL gateway modeclientz:fal_client.client is required for managed FAL gateway mode)r,   _client_maybe_retry_request_raise_for_statusSyncRequestHandleadd_hint_headeradd_priority_headeradd_timeout_headerzFfal_client.SyncClient._client is required for managed FAL gateway modezKfal_client.client request helpers are required for managed FAL gateway modezLfal_client.client.SyncRequestHandle is required for managed FAL gateway mode)r%   RuntimeErrorr   _queue_url_format_sync_client_http_clientr1   r2   _request_handle_class_add_hint_header_add_priority_header_add_timeout_header)selfr   r,   r   sync_client_classclient_modules         r   __init__z_ManagedFalSyncClient.__init__Z   sg   #JdCC$_```
Hd;; [\\\!@AQ!R!R--#666#D$5y$GG$+M;QSW$X$X!!(8KT!R!R%,]<OQU%V%V" '7H$ O O$+M;PRV$W$W!#*=:NPT#U#U $ghhh$,0F0Nlmmm%-mnnn .-r   r   N)pathhintwebhook_urlpriorityheadersstart_timeoutapplication	argumentsDict[str, Any]rC   rD   Optional[str]rE   rF   rG   Optional[Dict[str, str]]rH   Optional[Union[int, float]]c                  | j         |z   }	|r|	d|                    d          z   z  }	||	dt          d|i          z   z  }	t          |pi           }
|| j        |                     ||
           |,| j        t          d          |                     ||
           |,| j        t          d          |                     ||
           |                     | j	        d|	|t          | j        dd          |
	          }|                     |           |                                }|                     |d
         |d         |d         |d         | j	                  S )Nr   ?fal_webhookzGfal_client.client.add_priority_header is required for priority requestszEfal_client.client.add_timeout_header is required for timeout requestsPOSTdefault_timeoutg      ^@)jsontimeoutrG   
request_idresponse_url
status_url
cancel_url)rV   rW   rX   rY   r/   )r8   lstripr   dictr<   r=   r7   r>   r1   r:   r%   r9   r2   rT   r;   )r?   rI   rJ   rC   rD   rE   rF   rG   rH   urlrequest_headersr#   datas                r   submitz_ManagedFalSyncClient.submitt   s    ${2 	*3S))))C"3M;#?@@@@Cw}"-- 5 A!!$888(0"#lmmm%%h@@@$'/"#jkkk$$]ODDD,,D-/@%HH# - 
 
 	x(((}}))L)n-L)L)$ * 
 
 	
r   )r   r   r,   r   r   r   )rI   r   rJ   rK   rC   r   rD   rL   rE   rL   rF   r   rG   rM   rH   rN   )__name__
__module____qualname____doc__rB   r_    r   r   r+   r+   P   sh         o o o o> "%),059/
 /
 /
 /
 /
 /
 /
 /
r   r+   N)r	   r   )r   r   r	   r   )r   r    r	   r!   )rc   
__future__r   typingr   r   r   r   urllib.parser   r   r   r)   r+   rd   r   r   <module>rh      s    4 # " " " " " - - - - - - - - - - - - " " " " " "   ,# # # #   $S
 S
 S
 S
 S
 S
 S
 S
 S
 S
r   