Ë
    ãß²j¡­  ã                   ó\  — U d Z ddlZddlZddlZddlZddlZddlZddlmZm	Z	m
Z
 daeed<   defd„ZddlmZ ddlmZmZmZmZmZ dd	lmZmZmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z# dd
l$m%Z% ddl&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,  ejZ                  e.«      Z/ edd¬«      Z0da1da2 ejf                  «       Z4d„ Z5d„ Z6 G d„ de7«      Z8ddœde9fd„Z:de;de	e;ef   fd„Z<de;de
e;   fd„Z=d„ Z>d„ Z?de
e;   fd„Z@deAfd„ZBd d d!d"œZCdqde	e;ef   fd#„ZDeddfd$„ZEeddfd%„ZFd&e;d'e;de
e	e;ef      fd(„ZGh d)£ZHd*d*d*d+d,œZId-e;deJfd.„ZKd/e;dz  fd0„ZLd1ede;dz  fd2„ZMdqd3e;d/e;dz  de;fd4„ZNd5eOd6eJd7e;deOfd8„ZPd9„ ZQeddddddddf	d7e;d!e;d:e
eR   d;e
e9   d<e
eR   d=e
e;   d>e
eR   d&e
e;   d?e
eO   d@e
eJ   de;fdA„ZSdeJfdB„ZTde;fdC„ZUdDdEœdFe;dGeJfdH„ZVdeJfdI„ZWddJlXmYZYmZZZ dKdLdMdNdOdPœdN eOe#«      dQedRœdSœd7gdTœdUœZ[dVe;dWe;de;fdX„Z\dYe;de;fdZ„Z]dqde	e;ef   fd[„Z^	 	 drd7e;d!e;d&e
e;   d?e
eO   d@e
eJ   f
d\„Z_d]e
e;   de
e;   fd^„Z`de
eA   fd_„Za	 	 drd7e;d!e;d&e
e;   d?e
eO   d@e
eJ   de
e;   fd`„ZbdadbœdceAfdd„Zcde„ ZddfgddDdgœZede	e;ef   fdh„ZfdNdidPœZgdjdkdPœZhde	e;ef   fdl„Zi eYjÔ                  dKdme[edeWg dDdnei¬o«	       d]e
e;   deJfdp„Zky)sav  Image generation via FAL.ai (model picked in ``hermes tools``, persisted to ``image_gen.model``).

``_build_fal_payload()`` / ``_build_fal_edit_payload()`` translate unified inputs into the
``FAL_MODELS`` payload filtered to its ``supports`` whitelist so models never receive rejected
keys. Clarity upscaling is strictly per-call opt-in: default-on degraded text/CJK/faces.
é    N)ÚAnyÚDictÚOptionalÚ
fal_clientÚreturnc                  ó4   — t         €ddlm}   | «       a t         S )zZLazily import fal_client into the module global (idempotent; keeps a test-installed mock).r   ©Úimport_fal_client)r   Útools.fal_commonr
   r	   s    ú@/home/ubuntu/.hermes/hermes-agent/tools/image_generation_tool.pyÚ_load_fal_clientr      s   € ô ÐÝ6Ù&Ó(ˆ
ÜÐó    )ÚDebugSession)Ú_ManagedFalSyncClientÚ_extract_http_statusÚ_managed_fal_billing_errorÚ_normalize_fal_queue_url_formatÚ(submit_managed_fal_with_rate_limit_retry)ÚDEFAULT_ASPECT_RATIOÚDEFAULT_MODELÚ
FAL_MODELSÚUPSCALER_CREATIVITYÚUPSCALER_DEFAULT_PROMPTÚUPSCALER_FACTORÚUPSCALER_GUIDANCE_SCALEÚUPSCALER_MODELÚUPSCALER_NEGATIVE_PROMPTÚUPSCALER_NUM_INFERENCE_STEPSÚUPSCALER_RESEMBLANCEÚUPSCALER_SAFETY_CHECKERÚVALID_ASPECT_RATIOS)Úresolve_managed_tool_gateway)ÚNOUS_MANAGED_PROVIDERÚfal_key_is_configuredÚmanaged_nous_tools_enabledÚ%nous_tool_gateway_unavailable_messageÚread_selectionÚselection_errorÚimage_toolsÚIMAGE_TOOLS_DEBUG)Úenv_varc                  óð   — t        d«      } | t        k(  r)t        d«      }|€t        t	        dt        d«      «      ‚|S | �!t        «       ryt        t	        d| d«      «      ‚t        «       rdS t        d«      S )uŒ  Managed gateway config for the stored `hermes tools` selection, or ``None`` for direct FAL.

    ``"nous"`` (or legacy ``use_gateway: true``) â†’ managed ONLY (unreachable = selection-naming
    error, never a silent FAL_KEY fallback). Other stored provider â†’ direct ONLY (missing FAL_KEY
    = error naming the selection). Never configured â†’ autodetect: direct if FAL_KEY, else managed.
    Ú	image_genz	fal-queueNzDthe Nous Tool Gateway is not available (not entitled or unreachable)zFAL_KEY is not set)r'   r#   r"   Ú
ValueErrorr(   r$   )ÚselectedÚgateways     r   Ú_resolve_managed_fal_gatewayr1   7   s‡   € ô ˜kÓ*€HØÔ(Ò(Ü.¨{Ó;ˆØˆ?Üœ_ØÔ2ØVóXó Yð Yð ˆØÐÜ Ô"ØÜœ¨°hÐ@TÓUÓVÐVä(Ô*ˆ4ÐYÔ0LÈ[Ó0YÐYr   c                 ó
  — | j                   j                  d«      | j                  f}t        5  t        �	t
        |k7  r,t        t        «       | j                  | j                   ¬«      a|at        cddd«       S # 1 sw Y   yxY w)zQReuse the managed FAL client so its internal httpx.Client is not leaked per call.ú/N)ÚkeyÚqueue_run_origin)Úgateway_originÚrstripÚnous_user_tokenÚ_managed_fal_client_lockÚ_managed_fal_clientÚ_managed_fal_client_configr   r   )Úmanaged_gatewayÚclient_configs     r   Ú_get_managed_fal_clientr>   N   sy   € ð %×3Ñ3×:Ñ:¸3Ó?À×A`ÑA`Ða€MÜ	!ñ #ÜÐ&Ô*DÈÒ*Uä"7Ü Ó"¨×(GÑ(GØ!0×!?Ñ!?ô#AÐð *7Ð&Ü"÷#÷ #ò #ús   ®AA9Á9Bc                   ó   — e Zd ZdZy)ÚImageGenerationInterruptedz=Raised when the user interrupts while a FAL job is in flight.N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__© r   r   r@   r@   \   s   „ ÚGr   r@   g      à?)Úpoll_secondsrF   c                ó$  ‡ ‡‡— ddl m} g Šg Šˆˆ ˆfd„}t        j                  |dd¬«      }|j	                  «        |j                  «       r5 |«       rt        d«      ‚|j                  |¬«       |j                  «       rŒ5‰r‰d   ‚‰r‰d   S d	S )
zõInterrupt-aware ``handler.get()``: the SDK blocks 30-60s, hiding user interrupts.

    The get runs on a daemon worker; the interrupt bit is polled between join slices and on
    interrupt the worker is abandoned (remote job keeps running).
    r   )Úis_interruptedc                  ó”   •— 	 ‰j                  ‰j                  «       «       y # t        $ r} ‰j                  | «       Y d } ~ y d } ~ ww xY w©N)ÚappendÚgetÚBaseException)ÚexcÚ	error_boxÚhandlerÚ
result_boxs    €€€r   Ú_getz_wait_fal_result.<locals>._geti   s=   ø€ ð	"Ø×Ñ˜gŸk™k›mÕ,øÜò 	"Ø×Ñ˜S×!Ñ!ûð	"ús   ƒ# £	A¬AÁATzfal-result-wait)ÚtargetÚdaemonÚnameuI   Image generation interrupted by user â€” abandoned the in-flight FAL job.)ÚtimeoutN)Útools.interruptrH   Ú	threadingÚThreadÚstartÚis_aliver@   Újoin)rP   rF   rH   rR   ÚworkerrO   rQ   s   `    @@r   Ú_wait_fal_resultr^   `   s“   ú€ õ /Ø€JØ€Iö"ô
 ×Ñ T°$Ð=NÔO€FØ
‡L�L„NØ
�/‰/Ô
ÙÔÜ,Ø[ó]ð ]à�‰˜LˆÔ)ð	 �/‰/Õ
ñ
 Ø˜‰lÐÙ&ˆ:�a‰=Ð0¨DÐ0r   ÚmodelÚ	argumentsc           	      óÀ  ‡ ‡‡— t        «        dt        t        j                  «       «      i}t	        «       Š‰€t
        j                  ‰ ‰|¬«      S 	 t        ˆˆˆ fd„d‰ ¬«      S # t        $ ro}t        |«      }|�\d|cxk  rdk  rQn ‚ t        |d	«      }|�t        d
‰ › d|› d|› �«      |‚d}|dv rdt        dd¬«      z   }t        d
‰ › d|› d|› �«      |‚‚ d}~ww xY w)zKSubmit a FAL request using direct credentials or the managed queue gateway.zx-idempotency-keyN©r`   Úheadersc                 ó>   •— t        ‰«      j                  ‰‰| ¬«      S )Nrb   )r>   Úsubmit)rc   r`   r<   r_   s    €€€r   ú<lambda>z%_submit_fal_request.<locals>.<lambda>ƒ   s%   ø€ Ô3°OÓD×KÑKØ °Gð Ló =€ r   zimage model)ÚwhatrU   i�  iô  r_   z*Nous Subscription gateway rejected model 'z' (HTTP z): Ú >   é‘  é’  é“  z

úmanaged FAL image generationT)Úforce_freshuÓ   ). This model may not yet be enabled on the Nous Portal's FAL proxy. Either:
  â€¢ Set FAL_KEY in your environment to use FAL.ai directly, or
  â€¢ Pick a different model via `hermes tools` â†’ Image Generation.)r   ÚstrÚuuidÚuuid4r1   r   re   r   Ú	Exceptionr   r   r.   r&   )r_   r`   Úrequest_headersrN   ÚstatusÚbillingÚgateway_messager<   s   ``     @r   Ú_submit_fal_requestrv   z   s3  ú€ äÔØ*¬C´·
±
³Ó,=Ð>€OÜ2Ó4€OØÐÜ× Ñ  °)À_Ð ÓUÐUðÜ7õ=à Uô,ð 	,øô ò ô & cÓ*ˆØÐ #¨Ô"5°#Ô"5ð 	ô 1°°gÓ>ˆGØÐ"Ü Ø@ÀÀÀxÐPVÈxÐWZÐ[bÐZcÐdófØknðoà ˆOØ˜Ñ(Ø"(Ô+PØ2Àô,Fñ #F�äØ<¸U¸GÀ8ÈFÈ8ð TXð #Ð#ð	%ó&ð
 ,/ð/ð 	ûð'ús   ÁA% Á%	CÁ.A*CÃCr4   c                 óf  — 	 ddl m}  |«       }t        |t        «      r|j	                  d«      nd}t        |t        «      r|j	                  | «      nd}t        |t
        «      r |j                  «       r|j                  «       S y# t        $ r!}t        j                  d| |«       Y d}~yd}~ww xY w)zIReturn the stripped ``image_gen.<key>`` string from config.yaml, or None.r   )Úload_configr-   NzCould not read image_gen.%s: %s)
Úhermes_cli.configrx   Ú
isinstanceÚdictrL   rn   Ústriprq   ÚloggerÚdebug)r4   rx   ÚcfgÚsectionÚvaluerN   s         r   Ú_read_image_gen_keyr‚   �   s’   € ðBÝ1Ù‹mˆÜ*4°S¼$Ô*?�#—'‘'˜+Ô&ÀTˆÜ$.¨w¼Ô$=�—‘˜CÔ À4ˆÜ�eœSÔ! e§k¡k¤mØ—;‘;“=Ð ð øô ò BÜ�‰Ð6¸¸S×AÐAØûðBús   ‚BB Â	B0ÂB+Â+B0c                  ó   — t        d«      S )z.``image_gen.model`` from config.yaml, or None.r_   ©r‚   rE   r   r   Ú_read_configured_image_modelr…   «   s   € ä˜wÓ'Ð'r   c                  ó   — t        d«      S )u}  ``image_gen.provider`` from config.yaml, or None (unset keeps the in-tree FAL fallback even
    when other providers are registered; ``"fal"`` routes via ``plugins/image_gen/fal/``).

    We only consult the plugin registry when this is explicitly set â€” an unset value keeps users on the
    in-tree FAL fallback even when other providers happen to be registered (e.g. a user has OPENAI_API_KEY
    set for other features but never asked for OpenAI image gen). ``"fal"`` explicitly routes through
    ``plugins/image_gen/fal/`` (which delegates back into this module's pipeline via call-time indirection â€”
    see issue #26241).
    Úproviderr„   rE   r   r   Ú_read_configured_image_providerrˆ   °   s   € ô ˜zÓ*Ð*r   c                  ó4   — t        «       } | r
| dt        fv ry| S )zVConfigured provider that must go through the plugin registry; None for unset/fal/nous.ÚfalN)rˆ   r#   )Ú
configureds    r   Ú_plugin_provider_namerŒ   ½   s#   € ä0Ó2€JÙ˜¨Ô/DÐ'EÑEØØÐr   c                  óÜ   — t        d«      xs$ t        j                  dd«      j                  «       } | r%| t        vrt
        j                  d| t        «       d} | xs t        } | t        |    fS )znReturn ``(model_id, meta)`` for the configured FAL model, falling back to DEFAULT_MODEL (warned) when unknown.r_   ÚFAL_IMAGE_MODELrh   z4Unknown FAL model '%s' in config; falling back to %sN)r‚   ÚosÚgetenvr|   r   r}   Úwarningr   ©Úmodel_ids    r   Ú_resolve_fal_modelr”   Å   sc   € ô # 7Ó+ÒW¬r¯y©yÐ9JÈBÓ/O×/UÑ/UÓ/W€HÙ�H¤JÑ.Ü�‰ÐMÈxÔYfÔgØˆØÒ(œ=€HØ”Z Ñ)Ð)Ð)r   Ú
image_sizeÚaspect_ratio)Úimage_size_presetÚgpt_literalr–   c                 óT  — t         |    }|du}|r|j                  d«      xs t        «       n|d   }|d   }	|xs t        j	                  «       j                  «       }
|
|	vrt        }
t        |j                  di «      «      }|xs dj                  «       |d<   dh}|rG|j                  d«      xs d	}|d	k7  rt        |«      d
   n
t        |«      ||<   |j                  |«       t        j                  |d   «      }|€|st        d|d   ›�«      ‚|�|r||v r|	|
   ||<   t        |t        «      r||d<   |j                  |xs i j                  «       D ��ci c]  \  }}|€Œ	||“Œ c}}«       |j                  «       D ��ci c]  \  }}||v s||v sŒ||“Œ c}}S c c}}w c c}}w )a¡  Text-to-image / edit payload (``image_urls`` selects edit mode): defaults + native size
    spec + overrides, filtered to the model whitelist.

    Edit endpoints mostly auto-infer size, so the size key is sent only when ``edit_supports``
    lists it. ``prompt`` (and the source-image key on edits) survive a whitelist gap: every FAL
    endpoint requires them, so a catalog mistake can't send a broken request.
    NÚedit_supportsÚsupportsÚsizesÚdefaultsrh   ÚpromptÚedit_image_paramÚ
image_urlsr   Ú
size_stylezUnknown size_style: Úseed)r   rL   Úsetr   Úlowerr|   r{   ÚlistÚaddÚ_SIZE_KEY_BY_STYLEr.   rz   ÚintÚupdateÚitems)r“   rž   r–   r¢   Ú	overridesr    ÚmetaÚeditr›   rœ   ÚaspectÚpayloadÚrequiredÚimage_paramÚsize_keyÚkÚvs                    r   Ú_build_payloadrµ   Ô   s­  € ô �hÑ€DØ˜TÐ!€DÙ7;�—‘˜Ó)Ò2¬S¬UÀÀjÑAQ€HØ�‰M€EØÒ2Ô2×9Ñ9Ó;×AÑAÓC€FØ�UÑÜ%ˆÜ" 4§8¡8¨J¸Ó#;Ó<€GØš 2×,Ñ,Ó.€GˆHÑØˆz€HÙØ—h‘hÐ1Ó2ÒB°lˆØ6AÀ\Ò6Qœt JÓ/°Ò2ÔW[Ð\fÓWgˆ�ÑØ�‰�[Ô!Ü!×%Ñ% d¨<Ñ&8Ó9€HØÐ¡ÜÐ/°°\Ñ0BÐ/EÐFÓGÐGØÐ¡T¨X¸Ñ-AØ! &™Mˆ�ÑÜ�$œÔØˆ�‰Ø‡N�N i¢o°2×%<Ñ%<Ó%>×P™T˜Q À!Á-�A�q‘DÓPÔQØ$Ÿ]™]›_×O‘T�Q˜°°X±ÀÀhÂˆAˆq‰DÓOÐOùó QùÛOs   Å
F
Å$F
ÆF$ÆF$c                 ó    — t        | ||||«      S )z?FAL text-to-image payload for ``model_id`` from unified inputs.©rµ   )r“   rž   r–   r¢   r«   s        r   Ú_build_fal_payloadr¸   õ   s   € ä˜( F¨L¸$À	ÓJÐJr   c                 ó$   — t        | |||||¬«      S )z\FAL *edit* (image-to-image) payload: ``image_urls`` + prompt, filtered to ``edit_supports``.)r    r·   )r“   rž   r    r–   r¢   r«   s         r   Ú_build_fal_edit_payloadrº   ú   s   € ô ˜( F¨L¸$À	ÐV`ÔaÐar   Ú	image_urlÚoriginal_promptc                 ó@  — 	 t         j                  d«       t        t        | t        › d|› �t
        t        t        t        t        t        t        dœ	¬«      }t        |«      }|rod|v rk|d   }t         j                  d|j                  dd«      |j                  d	d«      «       |d
   |j                  dd«      |j                  d	d«      dt
        dœS t         j                  d«       y# t        $ r ‚ t         $ r"}t         j                  d|d¬«       Y d}~yd}~ww xY w)zPUpscale via FAL's Clarity Upscaler; None on failure (caller keeps the original).z(Upscaling image with Clarity Upscaler...z, )	r»   rž   Úupscale_factorÚnegative_promptÚ
creativityÚresemblanceÚguidance_scaleÚnum_inference_stepsÚenable_safety_checker©r`   Úimagez$Image upscaled successfully to %sx%sÚwidthÚunknownÚheightÚurlr   T)rÊ   rÇ   rÉ   Úupscaledr¾   z"Upscaler returned invalid responseNzError upscaling image: %s©Úexc_info)r}   Úinforv   r   r   r   r   r   r   r   r   r    r^   rL   Úerrorr@   rq   )r»   r¼   rP   ÚresultÚupÚes         r   Ú_upscale_imagerÓ     s  € ðÜ�‰Ð>Ô?Ü%¤nØ"Ô1HÐ0IÈÈOÐK\Ð.]Ü-ÔBZÜ-Ô>RÜ5Ü#?Ü%<ñA>ô ?ˆô " 'Ó*ˆÙ�g Ñ'Ø˜‘ˆBÜ�K‰KÐ>ØŸ™˜w¨	Ó2°B·F±F¸8ÀYÓ4OôQð ˜%‘y¨2¯6©6°'¸1Ó+=ÈÏÉÐPXÐZ[ÓI\Ø ´OñEð Eô 	�‰Ð9Ô:ØøÜ%ò àÜò Ü�‰Ð0°!¸dˆÔCÜûðús   ‚CC) ÃC) Ã)DÃ;DÄD>   ÚModalEnvironmentÚDockerEnvironmentÚSingularityEnvironmentú/root/.hermesz	~/.hermes)ÚdockerÚsingularityÚmodalÚsshr�   c                 óê   — | r/t        | t        «      r| j                  «       j                  d«      ryt        j
                  j                  | «      xs! t        | «      dk\  xr | d   dk(  xr | d   dv S )N)zhttp://zhttps://zdata:Fé   é   ú:é   >   r3   ú\)rz   rn   r¤   Ú
startswithr�   ÚpathÚisabsÚlen)r�   s    r   Ú_looks_like_absolute_file_pathræ   &  sb   € Ùœ
 5¬#Ô.°%·+±+³-×2JÑ2JÐKkÔ2lØÜ�7‰7�=‰=˜ÓÒd¤C¨£J°!¡OÒ$c¸¸a¹ÀC¹Ò$cÈEÐRSÉHÐXcÐLcÐdr   Útask_idc                 ó€   — 	 ddl m}  || xs d«      S # t        $ r }t        j	                  d|«       Y d }~y d }~ww xY w)Nr   )Úget_active_envÚdefaultz1Could not inspect active terminal environment: %s)Útools.terminal_tool_lifecycleré   rq   r}   r~   )rç   ré   rN   s      r   Ú_active_terminal_envrì   ,  s<   € ðÝ@Ù˜gÒ2¨Ó3Ð3øÜò Ü�‰ÐHÈ#ÔNÜûðús   ‚ ”	=�8¸=Úenvc                 óð  — | �†t        | dd «      }t        |«      r%	  |«       }|rt        |«      j                  d«      S 	 t        | dd «      }|rt        |«      j                  d«      › d�S | j                  j                  t        v ryddl
m}  |d	«      xs d
j                  «       j                  «       }t        j                  |«      S # t        $ r }t
        j                  d|«       Y d }~Œ°d }~ww xY w)NÚagent_visible_cache_baser3   z.active env agent_visible_cache_base failed: %sÚ_remote_homez/.hermesr×   r   ©Úterminal_envÚTERMINAL_ENVÚlocal)ÚgetattrÚcallablern   r7   rq   r}   r~   Ú	__class__rA   Ú_CONTAINER_HOME_ENVSÚtools.terminal_scoperò   r|   r¤   Ú_CACHE_BASE_BY_BACKENDrL   )rí   Úexplicitr�   rN   Úremote_homerò   Úbackends          r   Ú_agent_cache_base_for_envrþ   5  sê   € Ø
€ä˜3Ð :¸DÓAˆÜ�HÔðTÙ ›
�ÙÜ˜u›:×,Ñ,¨SÓ1Ð1ð ô ˜c >°4Ó8ˆÙÜ˜+Ó&×-Ñ-¨cÓ2Ð3°8Ð<Ð<Ø�=‰=×!Ñ!Ô%9Ñ9Ø"Ý1Ù˜NÓ+Ò6¨w×=Ñ=Ó?×EÑEÓG€GÜ!×%Ñ% gÓ.Ð.øô ò TÜ—‘ÐMÈs×SÑSûðTús   œ"C Ã	C5ÃC0Ã0C5Úrawc                 óì  — 	 t        | t        «      rt        j                  | «      n| }t        |t
        «      r|j                  d«      s| S |j                  d«      }t        |t        «      rt        |«      s| S t        |«      }t        |«      }|s| S 	 ddl
m}  |||¬«      }|r||k(  r| S t        |dd«      }	|	�	 |	j                  d	¬
«       |j#                  d|«       |j#                  d|«       t        j$                  |d¬«      S # t        $ r | cY S w xY w# t        $ r"}t        j                  d|«       | cY d}~S d}~ww xY w# t        $ r }t        j!                  d|«       Y d}~Œžd}~ww xY w)z«Annotate successful local results: ``image`` stays the host/gateway-deliverable path;
    ``agent_visible_image`` is the same file as seen by a non-local terminal backend.ÚsuccessrÆ   r   )Úmap_cache_path_to_container)Úcontainer_basez4Could not translate image cache path for backend: %sNÚ_sync_managerT©Úforcez1Could not force-sync generated image artifact: %sÚ
host_imageÚagent_visible_imageF)Úensure_ascii)rz   rn   ÚjsonÚloadsrq   r{   rL   ræ   rì   rþ   Útools.credential_filesr  r}   r~   rõ   Úsyncr‘   Ú
setdefaultÚdumps)
rÿ   rç   r¯   rÆ   rí   Ú
cache_baser  Ú
agent_pathrN   Úsync_managers
             r   Ú"_postprocess_image_generate_resultr  J  sa  € ðÜ%/°´SÔ%9”$—*‘*˜S”/¸sˆô �gœtÔ$¨G¯K©K¸	Ô,BØˆ
Ø�K‰K˜Ó €EÜ�eœSÔ!Ô)GÈÔ)NØˆ
Ü
˜wÓ
'€CÜ*¨3Ó/€JÙØˆ
ðÝFÙ0°ÀzÔRˆ
ñ ˜ uÒ,Øˆ
Ü˜3 °Ó6€LØÐð	UØ×Ñ DÐÔ)ð ×Ñ�| UÔ+Ø×ÑÐ,¨jÔ9Ü�:‰:�g¨EÔ2Ð2øô7 ò ØŠ
ðûô ò Ü�‰ÐKÈSÔQØ�
ûðûô ò 	UÜ�N‰NÐNÐPS×TÑTûð	UúsG   ‚'D ÂD Â>E
 ÄDÄDÄ	EÄ%EÄ<EÅEÅ
	E3ÅE.Å.E3ÚimagesÚshould_upscalerž   c           	      óD  — g }| D ]˜  }t        |t        «      rd|v sŒ|rFt        |d   |j                  «       «      }|r|j	                  |«       ŒKt
        j                  d«       |j	                  |d   |j                  dd«      |j                  dd«      ddœ«       Œš |S )zfNormalize FAL result images, optionally chaining the upscaler (falls back to the original on failure).rÊ   z1Using original image as fallback (upscale failed)rÇ   r   rÉ   F)rÊ   rÇ   rÉ   rË   )rz   r{   rÓ   r|   rK   r}   r‘   rL   )r  r  rž   Ú	formattedÚimgrË   s         r   Ú_format_imagesr  n  s£   € à€IØò  ˆÜ˜3¤Ô%¨%°3©,ØÙÜ% c¨%¡j°&·,±,³.ÓAˆHÙØ× Ñ  Ô*ØÜ�N‰NÐNÔOØ×ÑØ�u‘:¨¯©°¸Ó(;ÀsÇwÁwÈxÐYZÓG[Øñõ 	 ð ð Ðr   c           	      óà  — t        |t        «      r|j                  «       st        d«      ‚t	        «       st        «       st        t        «       «      ‚|j                  d«      |j                  d| «      }}|r|st        d|› d| › d�«      ‚|xs t        j                  «       j                  «       }	|	t        vr!t        j                  d|t        «       t        }	|rdt        |j                  d«      xs d	«      }
|
d
kD  r|d|
 n|}t        | |||	||¬«      }t        j                  d||t!        |«      |dd «       ||fS t#        | ||	||¬«      }t        j                  d|| |dd «       | |fS )zeValidate inputs and return ``(endpoint, arguments)``; raises ValueError with the user-facing message.z1Prompt is required and must be a non-empty stringÚedit_endpointÚdisplayzModel 'z' (u¦   ) is not capable of image-to-image / editing. Provide a text-only prompt (omit image_url), or switch to an edit-capable model via `hermes tools` â†’ Image Generation.z-Invalid aspect_ratio '%s', defaulting to '%s'Úmax_reference_imagesrÞ   r   N)r¢   r«   u=   Editing image with %s (%s) â€” %d source image(s), prompt: %séP   u,   Generating image with %s (%s) â€” prompt: %s)rz   rn   r|   r.   r$   r1   Ú_build_no_backend_setup_messagerL   r   r¤   r!   r}   r‘   r¨   rº   rÎ   rå   r¸   )r“   r¬   rž   r–   r¢   r«   Úsource_imagesr  r  Ú	aspect_lcÚmax_refsÚclamped_sourcesr`   s                r   Ú_prepare_fal_requestr$  €  st  € ä�fœcÔ"¨&¯,©,¬.ÜÐLÓMÐMô "Ô#Ô'CÔ'EÜÔ8Ó:Ó;Ð;Ø!ŸX™X oÓ6¸¿¹ÀÈHÓ8U�7€Má™]ÜØ�g�Y˜c ( ð ,7ð 8ó9ð 	9ð Ò5Ô!5×<Ñ<Ó>×DÑDÓF€IØÔ+Ñ+Ü�‰ÐFÈÔVjÔkÜ(ˆ	Ùä�t—x‘xÐ 6Ó7Ò<¸1Ó=ˆØ6>À²l˜-¨	¨Ñ2ÈˆÜ+Ø�f˜o¨y¸tÈyôZˆ	ä�‰ÐSØ˜]¬C°Ó,@À&ÈÈ"À+ô	Oà˜iÐ'Ð'Ü" 8¨V°YÀTÐU^Ô_€IÜ
‡K�KÐ>ÀÈÐSYÐZ]Ð[]ÐS^Ô_Ø�YÐÐr   rÃ   rÂ   Ú
num_imagesÚoutput_formatr¢   Úreference_image_urlsÚupscalec
                 ó&  ‡ — t        «       \  }
}t        |t        t        f«      r|ng }|g|¢­D �cg c]4  }t        |t        «      sŒ|j                  «       sŒ%|j                  «       ‘Œ6 }}t        |«      xr t        |j                  d«      «      }|rdnd}||||dœ}|
| |dœ|¥||t        |«      dœ¥ddd	d	d
œŠ t        j                  j                  «       }dt        dt        t        t        f   dt        fˆ fd„}	 t        |
|| |||j                  «       D ��ci c]  \  }}|€Œ	||“Œ c}}|«      \  }}t!        t#        ||¬«      «      }t        j                  j                  «       |z
  j%                  «       }|rd|vrt'        d«      ‚|j                  dg «      }|st'        d«      ‚|	�t        |	«      }n t        |j                  dd«      «      xr | }t)        ||| «      }|st'        d«      ‚t+        d„ |D «       «      }t,        j/                  dt        |«      ||||«       d‰ d<   t        |«      ‰ d<    ||d|d	   d   |t        |d	   j                  d«      «      dœ«      S c c}w c c}}w # t0        $ rŽ}dt	        |«      › �}t,        j3                  d|d¬«       |‰ d <   t        j                  j                  «       |z
  j%                  «       } ||ddt	        |«      t5        |«      j6                  d!œ«      cY d}~S d}~ww xY w)"a;  Generate (or, with source images + an ``edit_endpoint`` model, edit) an image via FAL.

    Extra kwargs are overrides filtered per-model via ``supports`` / ``edit_supports`` (dropped
    silently so callers survive model switches). Returns JSON ``{"success", "image", "modality",
    "error", "error_type"}``.
    r  rÆ   Útext)rÃ   rÂ   r%  r&  ©rž   r–   )r¢   Úmodalityr   NFr   )r_   Ú
parametersrÏ   r  Úimages_generatedÚgeneration_timer/  Úresponser   c                 ó’   •— | ‰d<   t         j                  d‰«       t         j                  «        t        j                  |dd¬«      S )Nr/  Úimage_generate_toolrà   F)Úindentr	  )Ú_debugÚlog_callÚsaver
  r  )r/  r0  Údebug_call_datas     €r   Úfinishz#image_generate_tool.<locals>.finish¼  s9   ø€ Ø-<ˆÐ)Ñ*Ü�‰Ð-¨Ô?Ü�‰ŒÜ�z‰z˜(¨1¸5ÔAÐAr   rÅ   r  u7   Invalid response from FAL.ai API â€” no images returnedzNo images were generatedr(  z%No valid image URLs returned from APIc              3   óD   K  — | ]  }|j                  d «      sŒd–— Œ y­w)rË   rÞ   N)rL   )Ú.0r  s     r   ú	<genexpr>z&image_generate_tool.<locals>.<genexpr>Õ  s   è ø€ ÒR 3¸c¿g¹gÀjÕ>QœQÑRùs   ‚ ™ z8Generated %s image(s) in %.1fs (%s upscaled) via %s [%s]Tr  r.  rÊ   rË   )r  rÆ   r,  rË   zError generating image: z%srÌ   rÏ   ©r  rÆ   rÏ   Ú
error_type)r”   rz   r¥   Útuplern   r|   ÚboolrL   rå   ÚdatetimeÚnowÚfloatr   r   r$  rª   r^   rv   Útotal_secondsr.   r  Úsumr}   rÎ   rq   rÏ   ÚtyperA   )!rž   r–   rÃ   rÂ   r%  r&  r¢   r»   r'  r(  r“   r¬   ÚrefsÚcr   Úuse_editr,  r«   Ú
start_timer8  r³   r´   Úendpointr`   rÐ   r/  r  r  Úformatted_imagesÚupscaled_countrÒ   Ú	error_msgr7  s!                                   @r   r2  r2  ¡  s7  ø€ ô (Ó)�N€HˆdÜ#-Ð.BÄTÌ5ÀMÔ#RÑÐXZ€DØ)2Ð(:°TÑ(:Ö_ 1¼jÈÌCÕ>PÐUV×U\ÑU\ÕU^�Q—W‘W•YÐ_€MÐ_Ü�MÓ"ÒF¤t¨D¯H©H°_Ó,EÓ'F€HÙ"‰w¨€Hà2ÀnØ °=ñ!B€Ið Ø!'¸ñ RÈð RÐ\`Ø#+¼cÀ-Ó>PòRà %¸QÐSTñ	V€Oô
 ×"Ñ"×&Ñ&Ó(€JðB¤ð B´´c¼3°h±ð BÄCõ Bð
$jÜ2Ø�d˜F L°$Ø'Ÿo™oÓ/×A‘d�a˜°1±=ˆQ�‰TÓAÀ=óRÑˆ�)ô "Ô"5°hÈ)Ô"TÓUˆÜ#×,Ñ,×0Ñ0Ó2°ZÑ?×NÑNÓPˆÙ˜¨Ñ/ÜÐVÓWÐWØ—‘˜H bÓ)ˆÙÜÐ7Ó8Ð8ð ÐÜ! '›]‰Nä! $§(¡(¨9°eÓ"<Ó=ÒNÀhÀ,ˆNÜ)¨&°.À&ÓIÐÙÜÐDÓEÐEÜÑRÐ*:ÔRÓRˆÜ�‰ÐNÜÐ(Ó)¨?¸NÈHÐV^ô	`à%)ˆ˜	Ñ"Ü.1Ð2BÓ.CˆÐ*Ñ+Ù�oØØ% aÑ(¨Ñ/Ø ÜÐ-¨aÑ0×4Ñ4°ZÓ@ÓAñ	(Có Dð 	DùòW `ùó* Bøô6 ò jØ.¬s°1«v¨hÐ7ˆ	Ü�‰�T˜9¨tˆÔ4Ø#,ˆ˜Ñ Ü#×,Ñ,×0Ñ0Ó2°ZÑ?×NÑNÓPˆÙ�oØ"'°$ÄÀQÃÔW[Ð\]ÓW^×WgÑWgÑhójõ 	jûðjúsI   ±I.ÁI.ÁI.ÄI9 Ä
I3Ä)I3Ä.D?I9 É3I9 É9	LÊBLÌLÌLc                  ód   — 	 t        «       } t        | «      xs
 t        «       S # t        $ r Y yw xY w)zòTrue if the selected FAL backend (never configured: any FAL backend) is available.

    A stored-but-broken selection reports False here (registry gating); the naming error
    surfaces at call time from ``_resolve_managed_fal_gateway``.
    F)r1   r.   r?  r$   )r0   s    r   Úcheck_fal_api_keyrO  è  s8   € ðÜ.Ó0ˆô �‹=Ò3Ô1Ó3Ð3øô ò Ùðús   ‚
# £	/®/c                  ó"  — t        «       } g d¢}| r|j                  d«       n2|j                  d«       t        d«      x}r|j                  d|› �«       |g d¢z  }| r|j                  d«       |j                  d«       d	j                  |«      S )
zXActionable no-backend error: FAL_KEY signup, managed-gateway status, plugin alternative.)z4Image generation is unavailable in this environment.rh   zMissing requirements:zA  - FAL_KEY is not set and the managed FAL gateway is unreachablez+  - FAL_KEY environment variable is not setrl   z  - )rh   z&To enable image generation, do one of:z_  1. Get a free API key at https://fal.ai and set FAL_KEY=<your-key> (then restart the session)zX  2. Sign in to a Nous account that has the managed FAL gateway enabled (`hermes setup`)u‹     3. Configure a different image_gen provider via `hermes tools` â†’ Image Generation (run `hermes plugins list` to see installed backends)Ú
)r%   rK   r&   r\   )ÚmanagedÚlinesru   s      r   r  r  õ  s˜   € ä(Ó*€GÚa€EÙØ�‰ÐXÕYà�‰ÐBÔCÜCÐDbÓcÐcˆ?ÐcØ�L‰L˜4 Ð0Ð1Ô2Ø	ò ,ñ ,€Eñ Ø�‰ð (ô 	)à	‡L�Lð Iô Jà�9‰9�UÓÐr   Fr  rU   r  c                óP   — ddl m} ddlm} |r
 |d¬«       n |«         || «      S )zpDiscover plugins (local import: importing this module must not trigger discovery) and return the named provider.r   )Úget_provider)Ú_ensure_plugins_discoveredTr  )Úagent.image_gen_registryrU  Úhermes_cli.pluginsrV  )rU   r  rU  rV  s       r   Ú_get_plugin_providerrY  
  s$   € å5Ý=ÙÙ"¨Ö.á"Ô$Ù˜ÓÐr   c                  ó¸   — 	 t        «       rt        «        y	 t        «       } | €yt	        | «      }t        |xr |j                  «       «      S # t        $ r Y Œ@w xY w)zDTrue if FAL or the explicitly configured image backend is available.TF)rO  r   ÚImportErrorrŒ   rY  r?  Úis_available)r‹   r‡   s     r   Ú#check_image_generation_requirementsr]    se   € ðÜÔäÔØð ô 'Ó(€JØÐØä# JÓ/€HÜ�Ò4˜X×2Ñ2Ó4Ó5Ð5øô ò Ùðús   ‚A Á	AÁA)ÚregistryÚ
tool_errorÚimage_generatezoGenerate images from text prompts. The active model's edit/reference capabilities are rendered at serving time.ÚobjectÚstringz€The text prompt describing the desired image (text-to-image) or the edit to apply (image-to-image). Be detailed and descriptive.)rE  ÚdescriptionzlThe aspect ratio of the generated image. 'landscape' is 16:9 wide, 'portrait' is 16:9 tall, 'square' is 1:1.)rE  Úenumrc  rê   r+  ©rE  Ú
propertiesr°   )rU   rc  r-  rÏ   r=  c                 ó6   — t        j                  dd| |dœ«      S )zCJSON error envelope shared by every provider-dispatch failure path.FNr<  )r
  r  )rÏ   r=  s     r   Ú_provider_errorrh  M  s   € ä�:‰: %°$ÀÐV`ÑaÓbÐbr   Úcontract_errorc                 ód   — t        | t        «      st        |d«      S t        j                  | «      S )zLJSON-encode a provider's dict result; anything else is a contract violation.Úprovider_contract)rz   r{   rh  r
  r  )rÐ   ri  s     r   Ú_provider_resultrl  R  s)   € ä�fœdÔ#Ü˜~Ð/BÓCÐCÜ�:‰:�fÓÐr   c                 óÈ   — |r|| d<   t        |t        «      r#|j                  «       r|j                  «       | d<   |�ddlm}  ||«      }|r|| d<   |�t        |«      | d<   | S )z^Add the optional ``provider.generate(**kwargs)`` args in place (edit args only when supplied).r_   r»   r   )Únormalize_reference_imagesr'  r(  )rz   rn   r|   Úagent.image_gen_providerrn  r?  )Úkwargsr»   r'  r(  r_   rn  Ú	norm_refss          r   Ú_add_provider_kwargsrr  Y  sm   € áØˆˆw‰Ü�)œSÔ! i§o¡oÔ&7Ø'Ÿo™oÓ/ˆˆ{ÑØÐ'ÝGÙ.Ð/CÓDˆ	ÙØ-6ˆFÐ)Ñ*ØÐÜ  ›MˆˆyÑØ€Mr   c                 óÎ  — t        «       }|€y	 t        |«      }|€	 t        |d¬«      }|€t        d|› d�d«      S t        |d	d
«      }| |dœ}		 t        |	|||t        «       ¬«        |j                  di |	¤Ž}
t        |
d«      S # t        $ r }t        j	                  d|«       Y d}~yd}~ww xY w# t        $ r }t        j	                  d|«       Y d}~Œ«d}~ww xY w# t        $ r~}t        |t        «      }|r4d|	v sd|	v r,t        j                  d||«       t        d|› d�d«      cY d}~S t        j                  d||rdnd|«       t        d|› d|› �d«      cY d}~S d}~ww xY w)zÂJSON result from the selected plugin provider, or ``None`` to fall through to in-tree FAL
    (provider unset / ``"fal"`` / ``"nous"``). Providers without ``upscale`` ignore it via ``**kwargs``.Nz%image_gen plugin dispatch skipped: %sTr  z*image_gen plugin force-refresh skipped: %szimage_gen.provider='zk' is set but no plugin registered that name. Run `hermes plugins list` to see available image gen backends.Úprovider_not_registeredrU   ú?r+  )r_   r»   r'  zQimage_gen provider '%s' rejected image-to-image kwargs (signature too narrow): %sz
Provider 'uè   ' does not support image-to-image / editing (its generate() signature is out of date with the image_generate schema). Omit image_url for text-to-image, or pick a backend that supports editing via `hermes tools` â†’ Image Generation.Úmodality_unsupportedz$Image gen provider '%s' raised%s: %sz
 TypeErrorrh   z	' error: Úprovider_exceptionz#Provider returned a non-dict resultrE   )rŒ   rY  rq   r}   r~   rh  rõ   rr  r…   Úgeneraterz   Ú	TypeErrorr‘   rl  )rž   r–   r»   r'  r(  r‹   r‡   rN   Úpnamerp  rÐ   Úis_type_errors               r   Ú_dispatch_to_plugin_providerr|  i  s¸  € ô
 'Ó(€JØÐØðÜ'¨
Ó3ˆð Ðð	LÜ+¨J¸dÔCˆHð ÐÜØ" : ,ð /Mð NØOhójð 	jô �H˜f cÓ*€EØ(.ÀÑM€FðYÜ˜V YÐ0DÀgÜ#?Ó#Aõ	Cà"�×"Ñ"Ñ, VÑ,ˆô  ˜FÐ$IÓJÐJøôG ò Ü�‰Ð<¸cÔBÜûðûô ò 	LÜ�L‰LÐEÀs×KÑKûð	Lûô ò Yô # 3¬	Ó2ˆÙ˜k¨VÑ3Ð7MÐQWÑ7WÜ�N‰Nð 8Ø9>ÀôEä"Ø˜U˜Gð $$ð %ð '=ó	>õ >ô
 	�‰Ð=¸uÙ'4‘|¸"¸cô	Cä ¨E¨7°)¸C¸5ÐAÐCWÓXÕXûðYúsY   �B �B1 Á*C Â	B.ÂB)Â)B.Â1	CÂ:CÃCÃ	E$Ã&A EÄ&E$Ä,-EÅE$ÅE$r“   c                 ób   — ddl m} t        | t        «      r| j	                  «       nd}||v r|S dS )zQReturn ``model_id`` when it is one of the Krea plugin's model ids, else ``None``.r   )ÚKREA_MODEL_IDSN)Úplugins.image_gen.krear~  rz   rn   r|   )r“   r~  Ú	candidates      r   Ú_normalize_krea_modelr�  ™  s.   € å5ä$.¨x¼Ô$=�—‘Ô À4€IØ! ^Ñ3ˆ9Ð=¸Ð=r   c                  óž   — ddl m} m}m} t	        «       }|�
|t
        k7  ryt        «       } ||«      }|| k(  rd|fS ||k(  r|t
        k(  rd|fS y)uƒ  ``(plugin_name, model_id)`` when the managed selection stores a Krea or Portal model, else ``None``.

    The managed row writes ``provider: nous`` for three gateways; the model id says which. FAL
    models (and an unset model) return ``None`` so the in-tree FAL path handles them. Only the
    ``nous``/unset selection qualifies â€” a direct/BYO provider pick dispatches normally.
    r   )ÚKREAÚPORTALÚmanaged_backend_for_modelNÚkreaÚnous)Útools.image_generation_managedrƒ  r„  r…  rˆ   r#   r…   )rƒ  r„  r…  Úconfigured_providerr“   rý   s         r   Ú_managed_model_pluginrŠ  ¡  si   € ÷ WÑVä9Ó;ÐØÐ&Ð+>ÔBWÒ+WØÜ+Ó-€HÙ'¨Ó1€GØ�$‚Ø�xÐÐØ�&ÒÐ0Ô4IÒIØ�xÐÐØr   c                 ó  — t        «       }|€y|\  }}	 |dk(  rddlm}  |«       €yt        |«      }	|	€|dk(  ryt        d|› d�d«      S | ||d	œ}	 t        ||||«        |	j                  di |¤Ž}t        ||	j                  › d�«      S # t        $ r#}
t
        j                  d||
«       d}	Y d}
~
Œd}
~
ww xY w# t        $ r=}
t
        j                  d
||
«       t        d|	j                  › d|
› �d«      cY d}
~
S d}
~
ww xY w)u1  JSON result from the Krea or Portal gateway the stored model belongs to, or ``None`` to fall
    through to FAL.

    A Krea model with no reachable Krea gateway falls through (direct/BYO users keep their
    pipeline); a Portal model never does â€” falling through would silently bill a FAL default.
    Nr†  r   )Ú_resolve_managed_krea_gatewayz"Managed %s routing unavailable: %szimage_gen.model='uƒ   ' is a Nous Portal model but the Portal image backend is not available. Pick another model via `hermes tools` â†’ Image Generation.rt  )rž   r–   r_   zManaged %s routing failed: %szManaged z generation error: rw  z$ provider returned a non-dict resultrE   )rŠ  r  rŒ  rY  rq   r}   r~   rh  rr  rx  r‘   Údisplay_namerl  )rž   r–   r»   r'  r(  rS   Úplugin_namer“   rŒ  r‡   rN   rp  rÐ   s                r   Ú_maybe_route_managed_modelr�  ¶  sD  € ô #Ó$€FØ€~ØØ"Ñ€K�ðØ˜&Ò ÝLÙ,Ó.Ð6ØÜ'¨Ó4ˆð ÐØ˜&Ò ØÜØ ˜zð *Uð VØWpórð 	rð )/ÀÐW_Ñ`€FðqÜ˜V YÐ0DÀgÔNØ"�×"Ñ"Ñ, VÑ,ˆô ˜F x×'<Ñ'<Ð&=Ð=aÐ$bÓcÐcøô! ò Ü�‰Ð9¸;ÈÔLØ�ûðûô ò qÜ�‰Ð6¸ÀSÔIÜ ¨(×*?Ñ*?Ð)@Ð@SÐTWÐSXÐYÐ[oÓpÕpûðqús:   ”B
 §B
 Á B9 Â
	B6ÂB1Â1B6Â9	C?Ã2C:Ã4C?Ã:C?)rÆ   ©Ú	permittedr‘  c          	      óî  ‡‡‡	‡
— ddl m}  |d«      xs dj                  «       j                  «       dv r| |dfS ddlmŠ	 ddlm}mŠ
 ˆ	ˆˆ
ˆfd	„}	 t        | t        «      r| j                  «       r || «      } t        |t        t        f«      r'|D �cg c]  }t        |t        «      r ||«      n|‘Œ }}| |dfS c c}w # |$ r/}| |t        d
|› �t        |«      j                  «      fcY d}~S d}~ww xY w)ar  Resolve path-like sources to ``data:`` URLs under a non-local terminal backend.

    Routes through ``tools.image_source`` (in-sandbox exec-read, media-cache host reads,
    credential guard) so generation obeys the same confinement as vision. URLs/data: pass
    through; local backend is a no-op. Returns ``(image_url, reference_image_urls, error_json_or_None)``.
    r   rñ   ró   rô   )rh   rô   N)Ú
_run_async)ÚImageResolutionErrorÚ resolve_local_source_to_data_urlc                 ó&   •—  ‰ ‰| ‰‰¬«      «      S )Nr�  rE   )Úrefr“  r‘  r•  rç   s    €€€€r   Úresolvez'_confine_source_images.<locals>.resolveé  s   ø€ ÙÑ:¸3ÀÐS\Ô]Ó^Ð^r   zCould not read source image: )rù   rò   r|   r¤   Úmodel_toolsr“  Útools.image_sourcer”  r•  rz   rn   r¥   r>  rh  rE  rA   )r»   r'  rç   r‘  rò   r”  r˜  ÚrrN   r“  r•  s     ``     @@r   Ú_confine_source_imagesrœ  Ü  s÷   û€ õ 2Ù�^Ó$Ò/¨×6Ñ6Ó8×>Ñ>Ó@ÀMÑQØÐ.°Ð4Ð4Ý&ßY÷_ðGÜ�i¤Ô%¨)¯/©/Ô*;Ù 	Ó*ˆIÜÐ*¬T´5¨MÔ:ØUiÖ#jÐPQ´*¸QÄÔ2D¡G¨A¤JÈ!Ñ$KÐ#jÐ Ð#jð Ð*¨DÐ0Ð0ùò	 $køØò GØÐ.´Ø+¨C¨5Ð1´4¸³9×3EÑ3Eó1Gð Gõ 	GûðGús1   ÁAC  Â!B;Â4C  Â;C  Ã C4Ã$C/Ã)C4Ã/C4c                 ó¼  — | j                  dd«      }|st        d«      S | j                  dt        «      }| j                  d«      }|j                  d«      }t        | j                  d«      | j                  d«      |«      \  }}}|�|S t	        ||t        |t        «      r|nd ¬	«      }	d }
t        t        t        fD ]  } |||fi |	¤Ž}
|
€Œ n t        |
|¬
«      S )Nrž   rh   z'prompt is required for image generationr–   r(  rç   r»   r'  )r»   r'  r(  )rç   )rL   r_  r   rœ  r{   rz   r?  r|  r�  r2  r  )ÚargsÚkwrž   r–   r(  rç   r»   r'  Úconfine_errorÚsourcesrÿ   Úroutes               r   Ú_handle_image_generater£  ö  sì   € Ø�X‰X�h Ó#€FÙÜÐCÓDÐDØ—8‘8˜NÔ,@ÓA€LØ�h‰h�yÓ!€GØ�f‰f�YÓ€Gä5KØ�‰�Ó˜tŸx™xÐ(>Ó?Àó6JÑ2€IÐ# ]àÐ ØÐô ˜YÐ=QÜ&0°¼$Ô&?™7ÀTôK€Gà
€CÜ.Ô0JÔL_Ð`ò ˆÙ�F˜LÑ4¨GÑ4ˆØ‰?Ùðô .¨c¸7ÔCÐCr   r*  )Ú
modalitiesr  Úsupports_upscalec                  ó  — t        t        «      } t        «       }t        «       }|�|d   }n|r|dk7  r|}nd}|r¹	 t	        |«      }|�ª	 |j                  «       xs i }|j                  | d<   t        «       xs |j                  «       xs d| d<   |j                  d«      rt        |d   «      | d<   |j                  d«      rt        |d   «      | d<   t        |j                  d	«      «      | d	<   | S 	 t        «       \  }}t        |j                  d
«      «      }d| d<   |j                  d|«      | d<   |rddgndg| d<   |rt        |j                  d«      xs d«      nd| d<   d| d	<   | S # t        $ r i }Y �Œw xY w# t        $ r Y Œ–w xY w)a;  Best-effort capabilities of the active backend/model; never raises.

    Mirrors runtime dispatch: a Krea or Portal model id under the managed selection asks that
    plugin, a set ``image_gen.provider`` asks that plugin, else the FAL catalog.
    Fail-closed: an undeclared capability is advertised as absent.
    Nr   rŠ   r‡   rh   r_   r¤  r  r¥  r  zFAL.air  r*  rÆ   rÞ   T)r{   Ú_NO_CAPABILITIESrˆ   rŠ  rY  Úcapabilitiesrq   r�  r…   Údefault_modelrL   r¥   r¨   r?  r”   )	rÎ   r‰  rR  rŽ  r‡   Úcapsr“   r¬   Úcan_edits	            r   Ú_active_image_capabilitiesr¬    s¾  € ô  Ô 0Ó1€DÜ9Ó;ÐÜ#Ó%€GØÐØ˜a‘j‰Ù	Ð!4¸Ò!=Ø)‰àˆÙð	Ü+¨KÓ8ˆHØÐ#ðØ#×0Ñ0Ó2Ò8°b�Dð $,×#8Ñ#8��ZÑ Ü <Ó >Ò bÀ8×CYÑCYÓC[ÒCaÐ_a��W‘Ø—8‘8˜LÔ)Ü)-¨d°<Ñ.@Ó)A�D˜Ñ&Ø—8‘8Ð2Ô3Ü36°tÐ<RÑ7SÓ3T�DÐ/Ñ0ä+/°·±Ð9KÓ0LÓ+M�Ð'Ñ(Ø�ð $ô" (Ó)�N€HˆdÜ�D—H‘H˜_Ó-Ó.€HØ€DˆÑØ—H‘H˜Y¨Ó1€Dˆ�MÙ.6˜& 'Ñ*¸V¸H€DˆÑÙQY¤3 t§x¡xÐ0FÓ'GÒ'LÈ1Ô#MÐ_`€DÐ	Ñ à#€DÐ	ÑØ€Køô- !ò Ø“Dðûô ò 	Ùð	ús6   »E> Á	E, ÁBE> Å,E;Å7E> Å:E;Å;E> Å>	F
Æ	F
z‹Source image to edit/transform (image-to-image). A public URL or an absolute local file path from the conversation. Omit for text-to-image.ÚbooleanuÎ   Post-generation high-resolution pass (~2x, extra cost/latency), off by default. A creative enhancer that can alter fine detail (rendered text, faces) â€” use only when resolution matters more than fidelity.c                  óx  — d} t        «       }t        |j                  d«      xs d«      }dt        |j                  d«      xs dg«      v }t        d   d   }|d	   |d
   dœ}|r!d}t
        |d<   |dkD  rdddi|d|› d�dœ|d<   nd}|j                  d«      r	t        |d<   | j                  |¬«      d|d	gdœdœS )z£Render description AND params from the active model's capabilities; args it cannot
    honor are NOT advertised (the handler still accepts them for replay compat).uÝ   Generate high-quality images from text prompts{edit_clause}. Returns the result in the `image` field â€” a URL or an absolute file path; reference it in your response using the current platform's file-delivery convention.r  r   rÆ   r¤  r*  r-  rf  rž   r–   r+  z<, or edit / transform an existing image by passing image_urlr»   rÞ   ÚarrayrE  rb  zUp to zn additional reference images (style, character, or composition) guiding an edit. URLs or absolute local paths.)rE  rª   ÚmaxItemsrc  r'  uF    (text-to-image only â€” the active model cannot edit existing images)r¥  r(  )Úedit_clausera  re  )rc  r-  )r¬  r¨   rL   r£   ÚIMAGE_GENERATE_SCHEMAÚ_IMAGE_URL_PARAMÚ_UPSCALE_PARAMÚformat)Ú	base_descrÎ   r"  r«  Ústatic_propsrf  r±  s          r   Ú_build_dynamic_image_schemar¸  X  s  € ð	/ð ô &Ó'€DÜ�4—8‘8Ð2Ó3Ò8°qÓ9€HØœ#˜dŸh™h |Ó4Ò@¸¸ÓAÐA€HÜ(¨Ñ6°|ÑD€Là˜xÑ(¸,À~Ñ:Vñ"X€JáØTˆÜ"2ˆ
�;ÑØ�aŠ<àØ  (Ð+Ø$à˜X˜Jð ',ð ,ñ	2ˆJÐ-Ò.ð _ˆØ‡x�xÐ"Ô#Ü .ˆ
�9ÑØ$×+Ñ+¸Ð+ÓDØ#+¸:ÐT\ÐS]Ñ^ñ`ð `r   r-   u   ðŸŽ¨)	rU   ÚtoolsetÚschemarP   Úcheck_fnÚrequires_envÚis_asyncÚemojiÚdynamic_schema_overridesc                 ó   — t        | «      duS )zATrue when ``model_id`` is a native Krea plugin id (``krea-2-*``).N)r�  r’   s    r   Úis_krea_modelrÁ  Š  s   € ä  Ó*°$Ð6Ð6r   rJ   )NNN)lrD   r
  Úloggingr�   r@  rX   ro   Útypingr   r   r   r   Ú__annotations__r   Útools.debug_helpersr   r   r   r   r   r   r   Útools.image_generation_catalogr   r   r   r   r   r   r   r   r   r   r   r    r!   Útools.managed_tool_gatewayr"   Útools.tool_backend_helpersr#   r$   r%   r&   r'   r(   Ú	getLoggerrA   r}   r4  r:   r;   ÚLockr9   r1   r>   rq   r@   rB  r^   rn   rv   r‚   r…   rˆ   rŒ   r>  r”   r§   rµ   r¸   rº   rÓ   rø   rú   r?  ræ   rì   rþ   r  r¥   r  r$  r¨   r2  rO  r  rY  r]  Útools.registryr^  r_  r²  rh  rl  rr  r|  r�  rŠ  r�  rœ  r£  r§  r¬  r³  r´  r¸  ÚregisterrÁ  rE   r   r   ú<module>rÍ     sw  ðòó Û Û 	Û Û Û ß &Ñ &ð €
ˆCÓ ð˜#ó õ -÷õ ÷÷ ÷ õ õ
 D÷L÷ Lð 
ˆ×	Ñ	˜8Ó	$€á	�mÐ-@Ô	A€ØÐ Ø!Ð Ø)˜9Ÿ>™>Ó+Ð òZò.#ôH ô Hð 8;ò 1¨uó 1ð4˜sð ¨t°C¸°H©~ó ðF˜Sð  X¨c¡]ó ò(ò

+ð˜x¨™}ó ð*˜Eó *ð ,8ÈØ&4ñ6Ð ñPÐX\Ð]`ÐbeÐ]eÑXfó PðB 7KÐQUÐaeó Kð
 H\Ø!%°óbð˜cð °Cð ¸HÀTÈ#ÈsÈ(Á^Ñ<Tó ò< [Ð ð %4ÀOØ#2¸;ñHÐ ðe¨#ð e°$ó eð #¨¡*ó ð/ 3ð /¨3°©:ó /ñ* 3¨Cð  3¸#À¹*ð  3ÐPSó  3ðH˜4ð °ð ¸sð Àtó ò$ðD &:Ø)-ÐQUØ $ÀTØ¸4Ø+/È4ñDjØðDjØ"ðDjà! #™ðDjà?GÈ¹ðDjð ˜‘ðDjð 6>¸c±]ðDjð �3‰-ð	Djð ,4°C©=ð	Djð
 # 4™.ðDjð
 ;CÀ4¹.ðDjð
 UXóDjðN
4˜4ó 
4ð¨ó ð* 6;ò ˜sð ¨dó ð6¨Tó 6÷$ 0ð ð	5ð ð !ð'ñð !ÙÐ0Ó1ð  NØ/ñ	ñ
ð$ �Jñ)ñ Ð ðHc˜3ð c¨Cð c°Có cð
¨Sð °Só ñÐZ^Ð_bÐdgÐ_gÑZhó ð" @DØKOñ-KØð-KØ"ð-KØ/7¸©}ð-Kà" 4™.ð-Kà:BÀ4¹.ó-Kð`> H¨S¡Mð >°h¸s±mó >ð˜x¨™ó ð, @DØKOñ#dØð#dØ"ð#dØ/7¸©}ð#dà" 4™.ð#dà:BÀ4¹.ð#dàT\Ð]`ÑTaó#dðL \fò 1ÐSXó 1ò4Dð6 $* (ÀAÐ[`ÑaÐ ð, D¨¨c¨¡Nó ,ðb ð	ñÐ ð ð	ñ€ð"` T¨#¨s¨(¡^ó "`ðJ €× Ñ Ø	 ;Ð7LØ"Ð-PÐ_aØØ
Ð+Fõ	ð7˜H S™Mð 7¨dô 7r   