Ë
    âß²j¢  ã                  ó|  — U 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Zddl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 ddlmZmZmZmZ  ej<                  e«      Z dZ!d	Z"e!e"fZ#e!de"d
iZ$ddddœZ%dZ&dZ'e!dddœe"dddœiZ(dZ)dZ*dZ+eZ,dZ-dZ.dZ/i Z0de1d<   dZ2dZ3dZ4d Z5d!d!d!d"d"d#œZ6d‚d$„Z7 e7d%d&e2d'd
d(¬)«       e7d*d+e2d,d
d(¬)«       e7d-d.d/e5d0d1d2d3¬4«       e7d5d6d7e5d8d1d2d3¬4«       e7d9d:e3d
d
¬;«       e7d<d=e3d
d
¬;«       e7d>d?d@dAd
d¬)«       e7dBdCe4d'd1d
d
¬D«       e7dEdFe4d'd1d
d
¬D«       e7dGdHdIdAd1dJdK¬D«      dLœ
Z8dMe1dN<    e7dOdOd!d
d3¬;«      Z9 e:h dP£«      Z;dQdRdSdTœZ<dUe1dV<   dWdXdXdYdZd[d\œZ= e:h d]£«      Z> e:e!e"h«      Z?d^Z@d_ZAd`dadb„ fdcdcdd„ ffZBdedfdgdhœZCdƒdi„ZDd„dj„ZEd…dk„ZFd†dl„ZGd‡dm„ZHdˆdn„ZI	 	 	 	 	 	 	 	 	 	 	 	 	 	 d‰do„ZJdŠdp„ZKd‹dq„ZLdŒdr„ZMd�ds„ZNdŽdt„ZO	 	 	 	 	 	 	 	 	 	 d�du„ZPddvœ	 	 	 	 	 	 	 	 	 	 	 	 	 d�dw„ZQ	 	 	 	 	 	 	 	 	 	 	 	 	 	 d‘dx„ZRd’dy„ZSd“d”dz„ZTd•d{„ZUd–d|„ZV	 	 	 	 	 	 	 	 	 	 	 	 d—d}„ZW G d~„ de«      ZXd˜d€„ZYd™d�„ZZy)šu  OpenRouter-compatible image generation backend (OpenRouter + Nous Portal).

Both speak the OpenAI-style ``/chat/completions`` image protocol (``modalities:
["image","text"]``, references as ``image_url`` parts, output in
``choices[0].message.images[].image_url.url``); only ``(base_url, api_key)`` differs,
via :func:`hermes_cli.runtime_provider.resolve_runtime_provider`. OpenRouter alone also
has the Dedicated Image API (``POST /images/generations``, own catalog, exact ratios,
up to 16 references) â€” see :func:`_select_surface`.
é    )ÚannotationsN)ÚPath)ÚAnyÚDictÚListÚOptionalÚTuple)ÚDEFAULT_ASPECT_RATIOÚImageGenProviderÚerror_responseÚresolve_aspect_ratioÚsave_b64_imageÚsave_url_imageÚsuccess_response)Úerror_factoryÚload_image_gen_configÚ	post_jsonÚrecord_token_usagezopenai/gpt-5.4-image-2zgoogle/gemini-3-pro-imageé   ú1:1ú16:9ú9:16)ÚsquareÚ	landscapeÚportraité   g     Àr@zOpenAI GPT-5.4 Image 2z=Highest fidelity; best prompt adherence; slower on OpenRouter©ÚdisplayÚ	strengthszGemini 3 Pro Imagez2Fast, reliable fallback with good layout adherence)zopenrouter/autog      $@ÚOPENROUTER_IMAGE_API_g      4@g      Œ@z8Dict[Tuple[str, Optional[str]], Tuple[float, frozenset]]Ú_CATALOG_CACHE)r   ú1:4ú1:8ú2:3ú3:2ú3:4ú4:1ú4:3ú4:5ú5:4ú8:1r   r   ú21:9)r   r(   r&   r   r   r%   r$   Úauto)r   r(   r%   r   r)   r$   r   )r-   ÚlowÚmediumÚhigh© F)ÚqualityÚ
backgroundÚoutput_formatÚcompressionÚseedc                ó$   — | |dœt         ¥ddi¥|¥S )zLCurated Image API model entry; unspecified knobs default to "not supported".r   Úresolutionsr1   )Ú	_NO_KNOBS)r   r   Úspecs      úJ/home/ubuntu/.hermes/hermes-agent/plugins/image_gen/openrouter/__init__.pyÚ_image_api_modelr<   P   s    € à¨YÑ_¼)Ð_À]ÐTVÑ_ÐZ^Ð_Ð_ó    z0Nano Banana 2 Lite (Gemini 3.1 Flash Lite Image)z;Cheap and fast; 14 exact aspect ratios; 14 reference images)Ú1Ké   )Úaspect_ratiosr8   Úmax_nÚmax_refsz&Nano Banana 2 (Gemini 3.1 Flash Image)z:Same ratios as Lite plus resolution control (512/1K/2K/4K))Ú512r>   Ú2KÚ4KzOpenAI GPT Image 2zFBest editing fidelity; up to 16 references; strongest prompt adherence)	r   r%   r$   r(   r&   r   r   r,   r-   )r-   ÚopaqueTé
   é   )r@   r2   r3   r5   rA   rB   zOpenAI GPT Image 1 Miniz=The only model here with background=transparent (cut-out PNG))r   r%   r$   r-   )r-   ÚtransparentrF   zMicrosoft MAI-Image-2.5z5Standard ratios; a good second opinion next to Gemini)r@   rA   rB   zMicrosoft MAI-Image-2.5 Proz.Reach for it when gpt-image-2 misses the briefzGrok Imagine (Image Quality)uA   Photoreal; widest exotic-ratio set (9:19.5, 20:9, 2:1 â€¦); 1K/2K)r   r&   r(   r   r   r$   r%   ú9:19.5ú19.5:9ú9:20ú20:9ú1:2ú2:1r-   )r>   rD   zKrea 2 Mediumz4Realistic, expressive styles; deterministic via seed)r@   r8   r6   rA   rB   zKrea 2 Medium Turbou?   Cheapest here â€” bulk content, cards, thumbnails; seed supportzQwen Image 3 Proz?Precise small text and detail rendering; n up to 6; 1K/2K; seed)r   rN   r"   rO   r$   r%   r&   r'   r(   r)   r*   r   r   é   é   )
z"google/gemini-3.1-flash-lite-imagezgoogle/gemini-3.1-flash-imagezopenai/gpt-image-2zopenai/gpt-image-1-minizmicrosoft/mai-image-2.5zmicrosoft/mai-image-2.5-prozx-ai/grok-imagine-image-qualityzkrea/krea-2-mediumzkrea/krea-2-medium-turbozqwen/qwen-image-3-proúDict[str, Dict[str, Any]]Ú_IMAGE_API_MODELSÚ >   r-   r   rN   r"   r#   rO   r$   r%   r&   r'   r(   r)   r*   r+   r   rM   r,   r   rL   ú9:21rK   rJ   )
r   r%   r(   r*   r,   rO   rK   rM   r'   r+   )
r   r$   r&   r)   rU   rN   rJ   rL   r"   r#   )r   )r   r   r   zDict[str, Tuple[str, ...]]Ú_ASPECT_PREFERENCESÚpngÚjpgÚwebpÚgifÚsvg)ú	image/pngz
image/jpegz	image/jpgz
image/webpz	image/gifzimage/svg+xml>
   é˜  é™  é©  é­  éô  éö  é÷  éø  é’  é”  )Ú
resolutionr2   r3   r4   r6   Ún))rg   r8   )r2   N)r3   N)r4   NÚoutput_compressionr5   c                ó.   — t        dt        d| «      «      S )Nr   éd   )ÚmaxÚmin©Úvs    r;   ú<lambda>rp   ©   s   € ´C¸¼3¸sÀA»;Ó4G€ r=   r6   c                ó   — | S ©Nr1   rn   s    r;   rp   rp   ©   s   € Ðef€ r=   zapplication/jsonz,https://github.com/NousResearch/hermes-agentzHermes Agent)zContent-TypezHTTP-RefererzX-Titlec                ó¶  — t        | xs d«      j                  «       } | sy| j                  d«      r| S t        | «      }ddlm}  || «       	 |j                  «       }t        j                  |j                  «      d   xs d}d|› d	t        j                  |«      j                  d
«      › �S # t        $ r!}t        j                  d| |«       Y d}~yd}~ww xY w)zUURLs pass through; local files inline as base64 data URIs (``None`` when unreadable).rT   N)zhttp://zhttps://údata:r   )Úraise_if_read_blockedz%could not read reference image %s: %sr\   rt   z;base64,Úascii)ÚstrÚstripÚ
startswithr   Úagent.file_safetyru   Ú
read_bytesÚOSErrorÚloggerÚdebugÚ	mimetypesÚ
guess_typeÚnameÚbase64Ú	b64encodeÚdecode)ÚrefÚpathru   ÚrawÚexcÚmimes         r;   Ú_to_image_url_partrŠ   ´   sÅ   € ä
ˆcŠi�R‹.×
Ñ
Ó
 €CÙØØ
‡~�~Ð6Ô7Øˆ
Ü�‹9€DÝ7á˜#ÔðØ�o‰oÓˆô ×Ñ §	¡	Ó*¨1Ñ-Ò<°€DØ�4�&˜¤×!1Ñ!1°#Ó!6×!=Ñ!=¸gÓ!FÐ GÐHÐHøô	 ò Ü�‰Ð<¸cÀ3ÔGÜûðús   ÁB. Â.	CÂ7CÃCc                óp   — t        | t        «      r| j                  |«      nd }t        |t        «      r|S i S rr   )Ú
isinstanceÚdictÚget©ÚnodeÚkeyÚvalues      r;   Ú_dict_atr“   È   ó.   € Ü'¨¬dÔ3ˆD�H‰H�SŒM¸€EÜ˜u¤dÔ+ˆ5Ð3°Ð3r=   c                óp   — t        | t        «      r| j                  |«      nd }t        |t        «      r|S g S rr   )rŒ   r�   rŽ   Úlistr�   s      r;   Ú_list_atr—   Í   r”   r=   c                ó  — g }t        | d«      D ]y  }t        t        |d«      d«      D ]^  }t        |d«      j                  d«      }t        |t        «      sŒ/|j                  «       sŒ@|j                  |j                  «       «       Œ` Œ{ |S )zGGenerated image URLs from ``choices[].message.images[].image_url.url``.ÚchoicesÚmessageÚimagesÚ	image_urlÚurl)r—   r“   rŽ   rŒ   rw   rx   Úappend)ÚpayloadÚoutÚchoiceÚimager�   s        r;   Ú_extract_imagesr£   Ò   s|   € à€CÜ˜7 IÓ.ò (ˆÜœh v¨yÓ9¸8ÓDò 	(ˆEÜ˜5 +Ó.×2Ñ2°5Ó9ˆCÜ˜#œsÕ#¨¯	©	­Ø—
‘
˜3Ÿ9™9›;Õ'ñ	(ð(ð
 €Jr=   c                óº   ‡— |j                  d«      sy|xs dj                  «       Š|dv xs t        ˆfd„dD «       «      }|sy| › d|› d|› d	| › d
|› dt        › d�S )z¤Hint for an access-gated OpenAI image model (valid key, but the *model* needs account
    enablement / BYOK, so "check your key" would mislead). ``None`` otherwise.zopenai/NrT   )re   é“  rf   c              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrr   r1   )Ú.0Úsr.   s     €r;   ú	<genexpr>z%_access_error_hint.<locals>.<genexpr>ã   s   øè ø€ ò -^ØˆˆSŒñ-^ùs   ƒ)zno endpointsz
no allowedznot a valid modelzdata policyz can't reach image model 'z' (u)   ) â€” enable OpenAI image access in your z account, or set Ú=ú.)ry   ÚlowerÚanyÚ_FALLBACK_MODEL)r   Úmodel_idÚenv_varÚstatusÚerr_msgÚgatedr.   s         @r;   Ú_access_error_hintr´   Ý   s�   ø€ ð ×Ñ˜yÔ)ØØŠ=�b×
Ñ
Ó
!€CØ�oÐ%ò ^¬ó -^Ø\ô-^ó *^€EáØàˆ)Ð-¨h¨Z°s¸6¸(ð C Ø '˜yÐ(9¸'¸À!ÄOÐCTÐTUð	WðXr=   c                ó~  — ddl }|j                  | › |› �|rdd|› �ini |¬«      }|j                  «        g }t        |j	                  «       d«      D ]h  }t        |t        «      r|j                  d«      nd}t        |t        «      sŒ7|j                  «       sŒH|j                  |j                  «       |f«       Œj |S )z_``(model_id, entry)`` pairs from ``GET {base_url}{path}``'s ``data[]``; raises on HTTP failure.r   NÚAuthorizationúBearer )ÚheadersÚtimeoutÚdataÚid)
ÚrequestsrŽ   Úraise_for_statusr—   ÚjsonrŒ   r�   rw   rx   rž   )	Úbase_urlr†   Úapi_keyr¹   r¼   Úresponser    Úentryr¯   s	            r;   Ú_get_catalogrÃ   ì   s³   € ãà�|‰|Øˆ*�T�FÐÉw o¸ÀÀ	Ð7JÑ%KÐ\^Ðhoð ó €Hð ×ÑÔØ,.€CÜ˜(Ÿ-™-›/¨6Ó2ò 2ˆÜ&0°¼Ô&=�5—9‘9˜T”?À4ˆÜ�h¤Õ$¨¯©Õ)9Ø�J‰J˜Ÿ™Ó(¨%Ð0Õ1ð2ð €Jr=   c          
     ó�  — g }t        | ||t        «      D ]®  \  }}t        |d«      }	|r-|j                  t        «      sd|	j                  d«      xs g vrŒA|j                  |i «      }
|j                  ||
j                  d|j                  d«      xs |«      |
j                  d|«      |	j                  d«      xs g dœ«       Œ° |S )	z²Picker rows from ``GET {base_url}{path}``; raises on failure. ``image_output_only`` keeps
    image-output models minus router pseudo-models; curated ``meta`` wins for known ids.Úarchitecturer¢   Úoutput_modalitiesr   r�   r   Úinput_modalities)r»   r   r   rÇ   )rÃ   Ú_LIVE_TIMEOUTr“   ry   Ú_EXCLUDED_MODEL_PREFIXESrŽ   rž   )r¿   rÀ   r†   ÚmetaÚgenericÚimage_output_onlyr    r¯   rÂ   ÚarchÚknowns              r;   Ú_fetch_catalogrÏ   ü   sÆ   € ð !#€CÜ'¨°$¸ÄÓOò ‰ˆ�%Ü˜˜~Ó.ˆÙØ×ÑÔ 8Ô9¸WÈTÏXÉXÐViÓMjÒMpÐnpÑ=qàØ—‘˜ 2Ó&ˆØ�
‰
ØØ—y‘y ¨E¯I©I°fÓ,=Ò,IÀÓJØŸ™ ;°Ó8Ø $§¡Ð);Ó <Ò BÀñ	
õ 	ðð €Jr=   c                ó¼  — ddl m} |  ||«      f}t        j                  |«      }|r&t	        j
                  «       |d   z
  t        k  r|d   S t        «       }	 t        | d|t        df«      }|D ��ch c]  \  }}|’Œ	 }}}t        |«      }
t	        j
                  «       |
ft        |<   |
S c c}}w # t        $ r!}	t        j                  d| |	«       Y d}	~	ŒUd}	~	ww xY w)uº   Model ids from ``GET {base_url}/images/models``, cached per (base URL, key). Any failure caches
    an empty set (â†’ chat-completions): guessing "images" would 404 a working chat setup.r   )Úfingerprint_secret_valuer   ú/images/modelsg      >@z)image API catalog probe failed for %s: %sN)Úagent.credential_persistencerÑ   r!   rŽ   ÚtimeÚ	monotonicÚ_CATALOG_TTL_SECONDSÚsetrÃ   Ú_IMAGE_API_CONNECT_TIMEOUTÚ	Exceptionr}   r~   Ú	frozenset)r¿   rÀ   rÑ   Ú	cache_keyÚcachedÚidsÚcatalogr¯   Ú_entryrˆ   Úresolveds              r;   Ú_fetch_image_api_catalográ     sÛ   € õ FàÑ3°GÓ<Ð=€IÜ×Ñ 	Ó*€FÙ”4—>‘>Ó# f¨Q¡iÑ/Ô3GÒGØ�a‰yÐÜ‹u€CðQÜ˜xÐ)9¸7ÔE_ÐaeÐDfÓgˆØ07×8Ñ,˜H fŠxÐ8ˆÑ8ô ˜‹~€HÜ!%§¡Ó!1°8Ð <„N�9ÑØ€Oùó 9øÜò QÜ�‰Ð@À(ÈC×PÑPûðQús*   ÁB1 Á2B+Á>B1 Â+B1 Â1	CÂ:CÃCc                ó6   — t         j                  | t        «      S )zECatalog metadata for *model_id*, or permissive defaults when unknown.)rS   rŽ   Ú_UNKNOWN_IMAGE_API_MODEL©r¯   s    r;   Ú_image_api_model_metarå   '  s   € ä× Ñ  Ô+CÓDÐDr=   c                ó   — | syt        dd|«      }t        |t        «      r>|j                  «       j	                  «       dv r|j                  «       j	                  «       S | t
        v ry| t        v s| t        ||«      v ryy)a	  ``"images"`` or ``"chat"``: config/env ``surface`` forces it; curated ids are offline and
    deterministic; unknown ids consult the cached live catalog (a positive probe must route there
    or a model the live picker offered would 404; offline they stay on chat).ÚchatÚsurfaceN>   rç   r›   r›   )Ú_image_api_settingrŒ   rw   rx   r¬   Ú_CHAT_ONLY_MODELSrS   rá   )r¯   r¿   rÀ   Ú
config_keyÚforceds        r;   Ú_select_surfacerí   ,  sy   € ñ ØÜ 	¨4°Ó<€FÜ�&œ#Ô 6§<¡<£>×#7Ñ#7Ó#9Ð=OÑ#OØ�|‰|‹~×#Ñ#Ó%Ð%ØÔ$Ñ$ØØÔ$Ñ$¨Ô4LÈXÐW^Ó4_Ñ(_ØØr=   c                ól  — |�"t        |t        «      r|j                  «       r|S t        j                  j                  t        › | j                  «       › �d«      j                  «       }|r|S t        t        «       |«      j                  | «      }t        |t        «      r|j                  «       xs dS |S )u]   Knob: call kwarg â†’ ``OPENROUTER_IMAGE_API_<NAME>`` env â†’ scoped config; blanks are unset.NrT   )
rŒ   rw   rx   ÚosÚenvironrŽ   Ú_IMAGE_API_ENV_PREFIXÚupperr“   Ú_load_image_gen_config)r�   Úexplicitrë   Ú	env_valuer’   s        r;   ré   ré   <  s�   € àÐ¤Z°¼#Ô%>ÀxÇ~Á~ÔGWØˆÜ—
‘
—‘Ô"7Ð!8¸¿¹»¸ÐGÈÓL×RÑRÓT€IÙØÐÜÔ+Ó-¨zÓ:×>Ñ>¸tÓD€EÜ&0°¼Ô&<ˆE�K‰K‹MÒ!˜TÐGÀ%ÐGr=   c                óÜ   — t        | t        «      ryt        | t        t        f«      rt        | «      S 	 t        | t        «      rt        | j                  «       «      S dS # t        $ r Y yw xY w)zHBest-effort int (env vars arrive as strings); ``None`` when not numeric.N)rŒ   ÚboolÚintÚfloatrw   rx   Ú
ValueError)r’   s    r;   Ú_coerce_intrû   G  s]   € ä�%œÔØÜ�%œ#œu˜Ô&Ü�5‹zÐðÜ%/°´sÔ%;Œs�5—;‘;“=Ó!ÐEÀÐEøÜò Ùðús   ´(A ÁA Á	A+Á*A+c                ó~  — t        |j                  d«      xs d«      }t        |t        «      rJ|j	                  «       r:|j	                  «       }|r||v s
|s
|t
        v r|S |j                  d|› d| › d�«       |s|j                  d| › d�«       yt        j                  | d«      D ]
  }||v sŒ|c S  d	|v rd	S |d
   S )zŸExact ``aspect_ratio`` or ``None`` to omit. *forced* wins when supported; otherwise the
    downgrade is noted and the per-model mapping of *semantic* applies.r@   r1   zrequested aspect_ratio 'z*' is unsupported by this model; used the 'z' mapping insteadzhmodel is not in this backend's catalog, so its aspect_ratio enum is unknown; the field was omitted and 'z' was not appliedNr-   r   )ÚtuplerŽ   rŒ   rw   rx   Ú_ENDPOINT_ASPECT_RATIOSrž   rV   )ÚsemanticrÊ   rì   ÚnotesÚ	supportedr’   Ú	candidates          r;   Ú_pick_exact_aspect_ratior  S  sã   € ô
 "' t§x¡x°Ó'@Ò'FÀBÓ!G€IÜ�&œ#Ô 6§<¡<¤>Ø—‘“ˆÙ˜% 9Ñ,±iÀEÔMdÑDdØˆLØ�‰Ø& u gð .Ø!˜
Ð"3ð5ô	6ñ à�‰ð3Ø3;°*Ð<MðOô	Pð Ü(×,Ñ,¨X°rÓ:ò ˆ	Ø˜	Ò!ØÒðð ˜yÑ(ˆ6Ð:¨i¸©lÐ:r=   ©Úmeta_keyc          
     óT  — t        | ||«      }t        |t        «      r|j                  «       sy|j                  «       }t	        |j                  |xs | «      xs d«      }|s|j                  d| › d�«       y||vr+|j                  d| › d|› ddj                  |«      › d�«       y|S )	zCResolve an enum knob and drop it when this model doesn't accept it.Nr1   ú'ú)' is not supported by this model; droppedrª   z'' is not valid for this model (accepts ú, z
); dropped)ré   rŒ   rw   rx   rý   rŽ   rž   Újoin)r�   rô   rÊ   rë   r   r  r’   Úalloweds           r;   Ú_image_api_enumr  l  s©   € ô
 ˜t X¨zÓ:€EÜ�eœSÔ!¨¯©¬ØØ�K‰K‹M€EÜ$ T§X¡X¨hÒ.>¸$Ó%?Ò%EÀ2ÓF€GÙØ�‰�q˜˜ÐGÐHÔIØØ�GÑØ�‰�q˜˜˜a ˜wÐ&MÈdÏiÉiÐX_ÓN`ÐMaÐakÐlÔmØØ€Lr=   c           	     óÌ  — t        | «      }g }| |dœ}t        d|j                  d«      |«      }	t        |||	|«      }
|
r|
|d<   t        D ]-  \  }}t        ||j                  |«      ||||¬«      }|sŒ)|||<   Œ/ t        D ]`  \  }}}t        t        ||j                  |«      |«      «      }|€Œ/|j                  |«      r ||«      ||<   ŒL|j                  d|› d�«       Œb t        t        d|j                  d«      |«      «      }|�Y|d	kD  rTt        |j                  d
«      xs d	«      }||kD  r|j                  d|› d|› d�«       t        d	t        ||«      «      |d<   |rxt        |j                  d«      xs d«      }|r|d| ng }t        |«      t        |«      kD  r |j                  t        |«      › d|› d�«       |r|D �cg c]	  }dd|idœ‘Œ c}|d<   ||fS c c}w )a  ``/images/generations`` body: ``(payload, notes)``. Every knob is filtered against what the
    model declares: the endpoint silently *ignores* unknown parameters, which would let a caller
    believe ``background=transparent`` took effect on a model without it.©ÚmodelÚpromptÚaspect_ratioÚaspect_ratio_exactr  Nr  r  rh   r   rA   z'n=z' exceeds this model's cap of z	; clampedrB   r   z4 reference image(s) supplied but this model accepts z; extras droppedrœ   r�   ©Útyperœ   Úinput_references)rå   ré   rŽ   r  Ú_IMAGE_API_ENUMSr  Ú_IMAGE_API_INTSrû   rž   rø   rl   rm   Úlen)r¯   r  Úsemantic_aspectÚ
referencesrë   ÚkwargsrÊ   r   rŸ   Úforced_ratioÚratioÚ	enum_namer  r’   r�   ÚgateÚclampÚcountrA   rB   Úusabler�   s                         r;   Ú_build_image_api_payloadr#    s  € ô ! Ó*€DØ€EØ(0¸FÑC€Gä% n°f·j±jÐAUÓ6VÐXbÓc€LÜ$ _°d¸LÈ%ÓP€EÙØ"'ˆ�ÑÜ/ò 'Ñˆ	�8Ü 	¨6¯:©:°iÓ+@À$È
ÐTYÐdlÔmˆÚØ!&ˆG�IÒð'ô -ò NÑˆˆd�EÜÔ.¨t°V·Z±ZÀÓ5EÀzÓRÓSˆØˆ=ØØ�8‰8�DŒ>Ù! %›LˆG�DŠMà�L‰L˜1˜T˜FÐ"KÐLÕMðNô Ô*¨3°·
±
¸3³ÀÓLÓM€EØÐ˜U QšYÜ�D—H‘H˜WÓ%Ò*¨Ó+ˆØ�5Š=Ø�L‰L˜3˜u˜gÐ%CÀEÀ7È)ÐTÔUÜ˜1œc %¨Ó/Ó0ˆ�‰ÙÜ�t—x‘x 
Ó+Ò0¨qÓ1ˆÙ*2�˜I˜XÑ&¸ˆÜˆz‹?œS ›[Ò(Ø�L‰LÜ�z“?Ð#ð $Ø#˜*Ð$4ð6ô7ñ ØgmÖ*nÐ`c°KÈuÐVYÈlÓ+[Ò*nˆGÐ&Ñ'Ø�Eˆ>Ðùò +os   Ç	G!c           	     óø  — | €|S 	 | j                  «       }t        |t        «      r|j                  d«      nd}t        |t        «      r |j                  «       r|j                  «       S t        |t        «      s|rt        j                  |«      dd S |S |j                  d«      }|j                  d«      dk(  r·t        |t        «      r§	 t        j                  |«      }t        |t        «      r|ng D �cg c]Y  }t        |t        «      rGd	j                  d
„ |j                  d«      xs g D «       «      xs d› d|j                  d«      xs d› �‘Œ[ }}dj                  |«      dd xs |dd S t        |t        «      r#|j                  «       r|j                  «       dd S t        j                  |«      dd S # t        $ r t        | dd«      xs ddd xs |cY S w xY w# t        $ r |dd cY S w xY wc c}w )zªOne-line error from ``{"error": {"message"}}`` (routing/auth) or the ZodError shape
    ``{"error": {"name": "ZodError", "message": "<json issue array>"}}`` (validation).NÚtextrT   i,  Úerrorrš   r�   ÚZodErrorr«   c              3  ó2   K  — | ]  }t        |«      –— Œ y ­wrr   ©rw   )r§   Úps     r;   r©   z+_extract_image_api_error.<locals>.<genexpr>Â  s   è ø€ ÒB 1œ˜AŸÑBùó   ‚r†   Úrequestz: Úinvalidz; i�  )r¾   rÙ   ÚgetattrrŒ   r�   rŽ   rw   rx   ÚdumpsÚloadsr–   r
  )rÁ   ÚfallbackÚbodyr&  rš   ÚissuesÚissueÚpartss           r;   Ú_extract_image_api_errorr6  ¬  sä  € ð ÐØˆðGØ�}‰}‹ˆô ",¨D´$Ô!7ˆD�H‰H�WÔ¸T€EÜ�%œÔ %§+¡+¤-Ø�{‰{‹}ÐÜ�eœTÔ"Ù)-Œt�z‰z˜$Ó  Ð%Ð;°8Ð;Ø�i‰i˜	Ó"€GØ‡y�y�Ó˜JÒ&¬:°g¼sÔ+Cð	!Ü—Z‘Z Ó(ˆFô %/¨v´tÔ$<™&À"ö
ð ÌÐTYÔ[_ÔI`ð �x‰xÑB¨¯©°6Ó):Ò)@¸bÔBÓBÒOÀiÐPÐPRØ�y‰y˜Ó#Ò0 yÐ1ò3ð
ˆð 
ð
 �y‰y˜Ó  Ð%Ò6¨°°#¨Ð6Ü�'œ3Ô G§M¡M¤OØ�}‰}‹˜t Ð$Ð$Ü�:‰:�eÓ˜T˜cÐ"Ð"øô- ò GÜ˜ &¨"Ó-Ò3°°T°cÐ:ÒF¸hÒFðGûô ò 	!Ø˜4˜C�=Ò ð	!üò
s*   †F< ÃG# Ã6AG7Æ<!G ÇG Ç#G4Ç3G4c                ó°   — t        | t        «      rEt        j                  | j	                  dd«      d   j                  «       j                  «       |«      S |S )Nú;r   r   )rŒ   rw   Ú_MEDIA_TYPE_EXTENSIONSrŽ   Úsplitrx   r¬   )Ú
media_typer1  s     r;   Ú_extension_forr<  Ì  sI   € Ü�*œcÔ"Ü%×)Ñ)¨*×*:Ñ*:¸3ÀÓ*BÀ1Ñ*E×*KÑ*KÓ*M×*SÑ*SÓ*UÐW_Ó`Ð`Ø€Or=   c                ó2   — dj                  d„ | D «       «      S )uI   Filename-safe fragment for the cache prefix (``openai/gpt-image-2`` â€¦).rT   c              3  óL   K  — | ]  }|j                  «       s|d v r|nd–— Œ y­w)z-_Ú_N)Úisalnum)r§   Úchs     r;   r©   z_model_slug.<locals>.<genexpr>Ô  s#   è ø€ ÒPÀ˜Ÿ™œ¨¨t©‘2¸Ó<ÑPùs   ‚"$)r
  rä   s    r;   Ú_model_slugrB  Ò  s   € à�7‰7ÑPÀxÔPÓPÐPr=   c                ón  — | j                  d«      }t        |t        «      r?|j                  «       r/t        t	        ||t        | j                  d«      «      ¬«      «      S | j                  d«      }t        |t        «      r4|j                  «       r$t        t        |j                  «       |¬«      «      S y)zNCache one ``data[]`` entry; ``None`` without b64/URL. Raises on write failure.Úb64_jsonr;  )ÚprefixÚ	extensionr�   ©rE  N)rŽ   rŒ   rw   rx   r   r<  r   )rÂ   rE  Úb64r�   s       r;   Ú_save_image_api_entryrI  ×  s€   € à
�)‰)�JÓ
€CÜ�#”sÔ §	¡	¤Ü”> #¨fÄÈuÏyÉyÐYeÓOfÓ@gÔhÓiÐiØ
�)‰)�EÓ
€CÜ�#”sÔ §	¡	¤Ü”> #§)¡)£+°fÔ=Ó>Ð>Ør=   c                óÐ  — d| j                  d«      dœ}|j                  t        D �ci c]  }|| v sŒ|| |   “Œ c}«       t        |«      dkD  r|dd |d<   |r!t        | j                  d«      xs g «      |d<   |r||d	<   t	        |d
«      }t        |j                  d«      t        t        f«      r|d   |d<   t        |j                  d«      t        «      r|d   |d<   |S c c}w )zLSuccess ``extra`` for an Image API result (knobs sent, extra images, usage).zimages/generationsr  )ÚendpointÚexact_aspect_ratior   NÚadditional_imagesr  Úreference_images_usedr   ÚusageÚcostÚcost_usdÚtotal_tokens)rŽ   ÚupdateÚ_IMAGE_API_EXTRA_KEYSr  r“   rŒ   rø   rù   )rŸ   ÚsavedÚusable_refsr   r2  Úextrar‘   rO  s           r;   Ú_image_api_extrarX  â  së   € ð *>ÐU\×U`ÑU`ÐaoÓUpÑq€EØ	‡L�LÔ/DÖW¨ÈÈwÊ�#�w˜s‘|Ñ#ÒWÔXÜ
ˆ5ƒz�A‚~Ø%*¨1¨2 YˆÐ!Ñ"ÙÜ),¨W¯[©[Ð9KÓ-LÒ-RÐPRÓ)SˆÐ%Ñ&ÙØˆˆg‰Ü�T˜7Ó#€EÜ�%—)‘)˜FÓ#¤c¬5 \Ô2Ø! &™MˆˆjÑÜ�%—)‘)˜NÓ+¬SÔ1Ø % nÑ 5ˆˆnÑØ€Lùò Xs
   ¨	C#²C#c                  ó2  — e Zd ZdZddœ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd„Zedd„«       Zedd„«       Zdd„Zdd„Z	dd	„Z
dd
„Zdd„Zdd„Zdd„Zdd„Zdd„Zd d!d„Zd d"d„Z	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d#d„Z	 	 	 	 	 	 	 	 	 	 	 	 	 	 d$d„Zefdddœ	 	 	 	 	 	 	 	 	 	 	 d%d„Zy)&ÚOpenRouterCompatImageProviderz°One instance per backend (OpenRouter, Nous Portal); they differ only in the runtime
    provider supplying ``(base_url, api_key)``, the config namespace, and Image API support.F)Úsupports_image_apic               ó‚   — || _         || _        || _        || _        || _        || _        d | _        d | _        || _        y rr   )	Ú_nameÚ_displayÚ_runtime_nameÚ_config_keyÚ_model_env_varÚ_setup_schemaÚ_live_models_cacheÚ_image_api_models_cacheÚ_supports_image_api)ÚselfÚprovider_nameÚdisplay_nameÚruntime_namerë   Úmodel_env_varÚsetup_schemar[  s           r;   Ú__init__z&OpenRouterCompatImageProvider.__init__ú  sJ   € ð #ˆŒ
Ø$ˆŒØ)ˆÔØ%ˆÔØ+ˆÔØ)ˆÔØ37ˆÔØ8<ˆÔ$Ø#5ˆÕ r=   c                ó   — | j                   S rr   )r]  ©rf  s    r;   r�   z"OpenRouterCompatImageProvider.name  s   € à�z‰zÐr=   c                ó   — | j                   S rr   )r^  rn  s    r;   rh  z*OpenRouterCompatImageProvider.display_name  s   € à�}‰}Ðr=   c                ó  — ddl m}  || j                  ¬«      }t        |j	                  d«      xs d«      j                  «       t        |j	                  d«      xs d«      j                  «       j                  d«      fS )uO   ``(api_key, base_url)`` â€” either may be ``""``; raises on resolution failure.r   )Úresolve_runtime_provider)Ú	requestedrÀ   rT   r¿   ú/)Úhermes_cli.runtime_providerrq  r_  rw   rŽ   rx   Úrstrip)rf  rq  Úruntimes      r;   Ú_credentialsz*OpenRouterCompatImageProvider._credentials  si   € åHá*°T×5GÑ5GÔHˆä�—‘˜IÓ&Ò,¨"Ó-×3Ñ3Ó5´s¸7¿;¹;ÀzÓ;RÒ;XÐVXÓ7Y×7_Ñ7_Ó7a×7hÑ7hÐilÓ7mð
ð 	
r=   c                óª   — 	 t        | j                  «       d   «      S # t        $ r+}t        j	                  d| j
                  |«       Y d }~yd }~ww xY w)Nr   z %s runtime resolution failed: %sF)r÷   rw  rÙ   r}   r~   r]  )rf  rˆ   s     r;   Úis_availablez*OpenRouterCompatImageProvider.is_available  sH   € ð	Ü˜×)Ñ)Ó+¨AÑ.Ó/Ð/øÜò 	Ü�L‰LÐ;¸T¿Z¹ZÈÔMÜûð	ús   ‚ ž	A§!AÁAc                ó´   — t         }| j                  r@| j                  «       d   }|t        v r%t	        t        |   j                  d«      xs |«      }ddg|dœS )Nr   rB   r%  r¢   )Ú
modalitiesÚmax_reference_images)Ú_MAX_REFERENCE_IMAGESre  Ú_resolve_model_chainrS   rø   rŽ   )rf  rB   rà   s      r;   Úcapabilitiesz*OpenRouterCompatImageProvider.capabilities   s\   € ä(ˆØ×#Ò#Ø×0Ñ0Ó2°1Ñ5ˆHØÔ,Ñ,ÜÔ0°Ñ:×>Ñ>¸zÓJÒVÈhÓW�Ø% wÐ/ÈÑRÐRr=   c                óÊ  — i }| j                   r!| j                  «       D �ci c]  }|d   |“Œ
 }}| j                  «       D ]  }|j                  |d   |«       Œ |rt	        |j                  «       d„ ¬«      S t        j                  «       D ��cg c]  \  }}d|i|¥‘Œ }}}| j                   r*|j                  d„ t        j                  «       D «       «       |S c c}w c c}}w )u¾   Live catalog: OpenRouter = ``GET /images/models`` âˆª chat-completions image models (new
        releases selectable); Nous Portal = chat-completions only. Offline: default chain + snapshot.r»   c                ó>   — t         j                  | d   d«      | d   fS )Nr»   é   )Ú_MODEL_PRIORITYrŽ   )Úms    r;   rp   z;OpenRouterCompatImageProvider.list_models.<locals>.<lambda>2  s%   € ¼/×:MÑ:MÈaÐPTÉgÐWXÓ:YÐ[\Ð]aÑ[bÐ9c€ r=   )r‘   c              3  ó@   K  — | ]  \  }}||d    |d   › d�dœ–— Œ y­w)r   r   z (Image API))r»   r   r   Nr1   )r§   r¯   rÊ   s      r;   r©   z<OpenRouterCompatImageProvider.list_models.<locals>.<genexpr>5  s8   è ø€ ò Aá"�H˜dð  ¨D°©OÈTÐR]ÑM^ÐL_Ð_kÐJlÕmñAùs   ‚)
re  Ú_image_api_live_modelsÚ_live_modelsÚ
setdefaultÚsortedÚvaluesÚ_KNOWN_MODEL_METAÚitemsÚextendrS   )rf  ÚmergedrÂ   r¯   rÊ   Úmodelss         r;   Úlist_modelsz)OpenRouterCompatImageProvider.list_models)  så   € ð -/ˆØ×#Ò#Ø6:×6QÑ6QÓ6SÖT¨U�e˜D‘k 5Ñ(ÐTˆFÐTØ×&Ñ&Ó(ò 	2ˆEØ×Ñ˜e D™k¨5Õ1ð	2áÜ˜&Ÿ-™-›/Ñ/cÔdÐdÜAR×AXÑAXÓAZ×[©~¨x¸�4˜Ð* TÒ*Ð[ˆÑ[Ø×#Ò#Ø�M‰Mñ Aä&7×&=Ñ&=Ó&?ôAô Að ˆùò Uùó
 \s   ¡CÂCc                ón  — t        | |«      }|�&t        j                  «       |d   z
  t        k  r|d   S g }	 | j	                  «       \  }}|rt        ||fi |¤Ž}t        | ||t        j                  «       f«       |S # t        $ r.}t        j                  d| j                  ||«       g }Y d}~ŒUd}~ww xY w)zMCached (per TTL) live catalog rows for this backend; ``[]`` when unreachable.Nr   r   z%s live %s unavailable: %s)r.  rÔ   rÕ   Ú_LIVE_CACHE_TTLrw  rÏ   rÙ   r}   r~   r]  Úsetattr)	rf  ÚattrÚlabelÚfetchrÜ   r�  rÀ   r¿   rˆ   s	            r;   Ú_cached_catalogz-OpenRouterCompatImageProvider._cached_catalog:  s³   € ä˜˜tÓ$ˆØÐ¤$§.¡.Ó"2°V¸A±YÑ">ÄÒ"PØ˜!‘9ÐØ')ˆð	Ø $× 1Ñ 1Ó 3ÑˆG�XÙÜ'¨°'ÑC¸UÑC�ô 	��d˜V¤T§^¡^Ó%5Ð6Ô7Øˆøô	 ò 	Ü�L‰LÐ5°t·z±zÀ5È#ÔNØ�Fûð	ús   ¸"A= Á=	B4Â$B/Â/B4c                ó8   — | j                  dddt        dd¬«      S )Nrd  zImage API catalogrÒ   z.Image API model (from live OpenRouter catalog)F©r†   rÊ   rË   rÌ   )r—  rS   rn  s    r;   r†  z4OpenRouterCompatImageProvider._image_api_live_modelsJ  s.   € Ø×#Ñ#Ø%Ð':ÐAQÔXiØDÐX]ð $ó _ð 	_r=   c                ó8   — | j                  dddt        dd¬«      S )Nrc  zimage model catalogz/modelsz1Image-output model (from live OpenRouter catalog)Tr™  )r—  r‹  rn  s    r;   r‡  z*OpenRouterCompatImageProvider._live_modelsO  s-   € Ø×#Ñ#Ø Ð"7¸iÔN_ØGÐ[_ð $ó að 	ar=   c                ó   — t         S rr   )ÚDEFAULT_MODELrn  s    r;   Údefault_modelz+OpenRouterCompatImageProvider.default_modelT  s   € äÐr=   c                óH   — | j                   rt        | j                   «      S d S rr   )rb  r�   rn  s    r;   Úget_setup_schemaz.OpenRouterCompatImageProvider.get_setup_schemaX  s    € Ø+/×+=Ò+=Œt�D×&Ñ&Ó'ÐGÀ4ÐGr=   Nc                ó*   — | j                  |«      d   S )Nr   )r~  )rf  rô   s     r;   Ú_resolve_modelz,OpenRouterCompatImageProvider._resolve_model[  s   € Ø×(Ñ(¨Ó2°1Ñ5Ð5r=   c                óÚ  — |t         j                  j                  | j                  «      fD ]6  }t	        |t
        «      sŒ|j                  «       sŒ%|j                  «       gc S  t        «       }t        || j                  «      j                  d«      |j                  d«      fD ]6  }t	        |t
        «      sŒ|j                  «       sŒ%|j                  «       gc S  t        t        «      S )u¯   ``model`` kwarg â†’ ``*_IMAGE_MODEL`` env â†’ ``image_gen.<provider>.model`` â†’
        ``image_gen.model`` â†’ default chain. Only the bare default chain carries a fallback.r  )rï   rð   rŽ   ra  rŒ   rw   rx   ró   r“   r`  r–   Ú_DEFAULT_MODEL_CHAIN)rf  rô   r  Úcfgs       r;   r~  z2OpenRouterCompatImageProvider._resolve_model_chain^  s¿   € ð #¤B§J¡J§N¡N°4×3FÑ3FÓ$GÐHò 	+ˆIÜ˜)¤SÕ)¨i¯o©oÕ.?Ø!Ÿ™Ó)Ð*Ò*ð	+ô %Ó&ˆÜ" 3¨×(8Ñ(8Ó9×=Ñ=¸gÓFÈÏÉÐPWÓHXÐYò 	+ˆIÜ˜)¤SÕ)¨i¯o©oÕ.?Ø!Ÿ™Ó)Ð*Ò*ð	+ô Ô(Ó)Ð)r=   c               óà  ‡‡— t        | j                  |||¬«      Šd-d.ˆfd„}g }	g }
	 |D ]/  }t        |«      }|r|	n|
j                  |xs t	        |«      «       Œ1 	 |
r |	s |ddj                  |
«      z   dz   d«      S t        ||||	| j                  |¬	«      \  }}|
r$|j                  d
ddj                  |
«      › �«       t        }t        d|j                  d«      | j                  «      }	 |�t        dt        |«      «      }t'        |› d�||t)        t*        |«      |f| j,                  d„ d¬«      \  }}|�Ç|j.                  dk7  r, ||j0                  |j2                  |j.                  dk(  ¬«      S |j4                  |j6                  }}t"        j1                  d| j                  |||«       |dv r || j,                  › d|› d|› �d«      S |dk(  r |d|› d|› d�dd¬«      S  ||j0                  d|t8        v ¬«      S t;        t=        |d «      || j                  |¬!«       t?        |d"«      D �cg c]  }tA        |tB        «      sŒ|‘Œ }}|s || j,                  › d#|› d$�d%d¬«      S | j                  › d&tE        |«      › �Š	 ˆfd'„|D «       D �cg c]  }|sŒ|‘Œ	 }}|s || j,                  › d)�d%«      S tG        |d
   |||| j                  |	rd*nd+tI        |||	||«      ¬,«      S # t
        $ r} |d|› �d«      cY d}~S d}~ww xY w# t        t         f$ r% t"        j%                  d| j                  |«       Y �Œ9w xY wc c}w c c}w # t
        $ r} |d(|› �d«      cY d}~S d}~ww xY w)/z™One ``POST {base_url}/images/generations`` attempt; a chain-retryable failure carries a
        private ``_retryable`` flag that :meth:`generate` strips.r  c                ó(   •—  ‰| |«      }|rd|d<   |S )NTÚ
_retryabler1   )r&  Ú
error_typeÚ	retryablerÁ   Ú	base_fails       €r;   Ú_failzDOpenRouterCompatImageProvider._generate_via_image_api.<locals>._failr  s!   ø€ Ù  ¨
Ó3ˆHÙØ)-�˜Ñ&ØˆOr=   z Could not load reference image: Úio_errorNz=Could not read the reference image(s) requested for editing: r	  z2. Refusing to silently fall back to text-to-image.)r¯   r  r  r  rë   r  r   z'dropped unreadable reference image(s): r¹   g      ð?z-%s: ignoring non-numeric image API timeout %rz/images/generationsc                ó,   — t        | t        |«      «      S rr   )r6  rw   )Úresprˆ   s     r;   rp   zGOpenRouterCompatImageProvider._generate_via_image_api.<locals>.<lambda>™  s   € Ô,DÀTÌ3ÈsË8Ó,T€ r=   T)r¸   rŸ   r¹   r•  Úerror_messageÚcatch_request_exceptionÚhttp)r©  z-%s image API generation failed (%s) on %s: %s)i‘  r¥   z rejected the API key (z): Ú
auth_errorrf   zModel 'uj   ' does not exist on the OpenRouter Image API (its catalog is separate from chat-completions â€” check GET z/images/models).Úmodel_accessÚ	api_errorrO  ©r  Úproviderr¿   rº   z returned no image data for 'z'.Úempty_responser?  c              3  ó6   •K  — | ]  }t        |‰«      –— Œ y ­wrr   )rI  )r§   ÚerE  s     €r;   r©   zHOpenRouterCompatImageProvider._generate_via_image_api.<locals>.<genexpr>´  s   øè ø€ Ò SÀaÔ!6°q¸&×!AÑ Sùs   ƒú Could not save generated image: z+ response carried neither b64_json nor url.r¢   r%  )r¢   r  r  r  r¶  ÚmodalityrW  )F)r&  rw   r¨  rw   r©  r÷   ÚreturnúDict[str, Any])%r   r]  rŠ   rž   rw   rÙ   r
  r#  r`  ÚinsertÚ_REQUEST_TIMEOUTré   rŽ   rl   rù   Ú	TypeErrorrú   r}   r~   r   rm   rØ   r^  Úkindr&  r¨  r±   rš   Ú_IMAGE_API_FALLBACK_STATUSESr   r“   r—   rŒ   r�   rB  r   rX  )rf  r¯   r  r  r  r¿   r¸   r  r«  rV  Ú
unreadabler…   Úpartrˆ   rŸ   r   r¹   Ú
configuredr2  Úfailurer±   rš   r¹  Úentriesr*  rU  rª  rE  s                             @@r;   Ú_generate_via_image_apiz5OpenRouterCompatImageProvider._generate_via_image_apij  sÌ  ù€ ô " $§*¡*¨oÀXÐV\Ô]ˆ	ö	ð "$ˆØ "ˆ
ð	OØ!ò O�Ü)¨#Ó.�Ù $‘¨*×<Ñ<¸TÒ=MÄSÈÃXÕNñOñ ™kÙØOØ—)‘)˜JÓ'ñ(Ø*^ñ_àóð ô 2Ø f¸oØ"¨t×/?Ñ/?ÈôP‰ˆ�ñ Ø�L‰L˜ÐEÀdÇiÁiÐPZÓF[ÐE\Ð]Ô^ä"ˆÜ'¨	°6·:±:¸iÓ3HÈ$×JZÑJZÓ[ˆ
ð	bØÐ%Ü˜c¤5¨Ó#4Ó5�ô
 "ØˆjÐ+Ð,°gÀwÜÔ3°WÓ=¸wÐGÈtÏ}É}ÙTØ$(ô	*‰ˆˆgð
 ÐØ�|‰|˜vÒ%Ù˜WŸ]™]¨G×,>Ñ,>È'Ï,É,ÐZcÑJcÔdÐdØ%Ÿn™n¨g¯o©o�GˆFÜ�L‰LÐHÈ$Ï*É*ÐV\Ð^fÐhoÔpà˜Ñ#Ù §¡˜Ð.EÀfÀXÈSÐQXÐPYÐZÐ\hÓiÐiØ˜Š}ÙØ˜h˜Zð (à#˜*Ð$4ð6ð #¨dô	4ð 4ñ
 ˜Ÿ™¨¸vÔIeÐ?eÔfÐfô 	œ8 D¨'Ó2¸(ÈTÏZÉZÐbjÕkÜ& t¨VÓ4ÖL˜¼
À1ÄdÕ8K’1ÐLˆÐLÙÙØ—=‘=�/Ð!>¸x¸jÈÐKÐM]Ðimôð ð —J‘J�<˜q¤¨XÓ!6Ð 7Ð8ˆð	OÛ SÈ7Ô SÖY˜1ÒWX’QÐYˆEÐYñ Ù˜DŸM™M˜?Ð*UÐVÐXhÓiÐiÜØ˜‘( (°6ÈÐbf×blÑblÙ +‘W°Ü" 7¨E°;ÀÀtÓLôNð 	Nøôu ò 	OÙÐ;¸C¸5ÐAÀ:ÓNÕNûð	Oûô& œ:Ð&ò 	bÜ�L‰LÐHÈ$Ï*É*ÐV`×að	büò6 Mùò ZøÜò 	OÙÐ;¸C¸5ÐAÀ:ÓNÕNûð	Oúsq   ¨4K+ Ã0L È4MÉ
MÊM ÊM	ÊM	Ê!M Ë+	L
Ë4LË?L
ÌL
Ì0MÍ MÍ	M Í	M-ÍM(Í"M-Í(M-c               ó>  — t        | j                  |||¬«      }|ddgd|dœgdt        j                  |d«      idœ}t	        |› d	�||t
        | j                  ¬
«      \  }	}
|
�Á|
j                  dk7  r2|
j                  dk(  rdnd} ||
j                  |
j                  «      |fS |
j                  |
j                  }}t        j                  d| j                  |||«       t        | j                  || j                  ||«      }|r ||d«      dfS  ||
j                  d«      dfS t        t!        |	d«      || j                  |¬«       t#        |	«      }|s || j                  › d|› d�d«      dfS |d   }	 |j%                  d«      r6d|v r|j'                  dd«      d   nd}t)        || j                  › d�¬«      }nt+        || j                  › d�¬«      }t/        t1        |«      |||| j                  ¬"«      dfS # t,        $ r} |d |› �d!«      dfcY d}~S d}~ww xY w)#z†One ``/chat/completions`` attempt: ``(result, retry_reason)``; reason set when the
        chain may continue with the fallback model.r  r¢   r%  Úuser)ÚroleÚcontentr  r   )r  r{  ÚmessagesÚimage_configz/chat/completions)r¸   rŸ   r¹   r•  Nr±  r¹   z	timed outz"%s image gen failed (%d) on %s: %sr³  Úunavailabler´  rO  rµ  z& returned no image. Ensure the model 'z' supports image output.r·  zreturned no imager   rt   ú,r   rT   Ú_genrG  rº  r¬  )r¢   r  r  r  r¶  )r   r]  Ú_ASPECT_RATIOSrŽ   r   r¿  r^  rÁ  r&  r¨  r±   rš   r}   r´   ra  r   r“   r£   ry   r:  r   r   rÙ   r   rw   )rf  r¯   r  ÚaspectrÌ  r¿   r¸   ÚfailrŸ   ÚresultrÆ  Úreasonr±   rš   Úhintr›   ÚfirstrH  Ú
saved_pathrˆ   s                       r;   Ú_generate_via_chatz0OpenRouterCompatImageProvider._generate_via_chat¾  sH  € ô ˜TŸZ™Z¨°xÈÔOˆàØ" FÐ+Ø"(°WÑ=Ð>Ø+¬^×-?Ñ-?ÀÈÓ-NÐOñ	#
ˆô $ØˆjÐ)Ð*°GÀWÔVfØ—-‘-ô!‰ˆ�ð ÐØ�|‰|˜vÒ%Ø(/¯©¸	Ò(A™Àt�Ù˜GŸM™M¨7×+=Ñ+=Ó>ÀÐFÐFØ%Ÿn™n¨g¯o©o�GˆFÜ�L‰LÐ=¸t¿z¹zÈ6ÐS[Ð]dÔeÜ% d§m¡m°X¸t×?RÑ?RÐTZÐ\cÓdˆDÙÙ˜D .Ó1°=Ð@Ð@Ù˜Ÿ™ {Ó3°TÐ9Ð9ô 	œ8 F¨GÓ4¸HÈtÏzÉzÐdlÕmÜ  Ó(ˆÙáØ—=‘=�/Ð!GÈÀzÐQiÐjØ óð #ð#ð #ð �q‘	ˆð	TØ×Ñ Ô(Ø03°u±�e—k‘k # qÓ)¨!Ò,À"�Ü+¨C¸4¿:¹:¸,ÀdÐ8KÔL‘
ä+¨E¸T¿Z¹Z¸LÈÐ:MÔN�
ô  Ü�j“/¨¸&ÈvÐ`d×`jÑ`jô
àðð 	øô ò 	TÙÐ:¸3¸%Ð@À*ÓMÈtÐSÕSûð	Tús   Å5A!G; Ç;	HÈHÈHÈH)rœ   Úreference_image_urlsc          
     óÒ  — t        | j                  |«      }	 | j                  «       \  }}|r|s$ |d| j                  › d| j                  › d�d«      S | j                  |j                  d«      «      }
t        |«      }|j                  d«      xs g D �cg c]  }t        |«      ‘Œ }}|r|j                  t        |«      «       |j                  d	„ |xs g D «       «       d
|dœg}|d t         D ]&  }t        |«      }|sŒ|j                  dd|idœ«       Œ( dd|› �it        ¥}d }t        |
«      D ]Ì  \  }}d}| j                  rt!        |||| j"                  «      }|dk(  r/| j%                  |||||||¬«      }|j'                  dd«      rdnd }n| j)                  ||||||¬«      \  }}|j                  d«      s|�|t+        |
«      dz
  k(  r|c S t,        j/                  d| j                  |||
|dz      «       |}ŒÎ |xs/ t1        | j                  › d�d| j                  |
r|
d   nd||¬«      S # t        $ r#}	 |d| j                  › d|	› �d«      cY d }	~	S d }	~	ww xY wc c}w ) NzCould not resolve z credentials: Úmissing_api_keyzNo z credentials found. Configure u(    in `hermes tools` â†’ Image Generation.r  Úreference_imagesc              3  ó2   K  — | ]  }t        |«      –— Œ y ­wrr   r)  )r§   r…   s     r;   r©   z9OpenRouterCompatImageProvider.generate.<locals>.<genexpr>  s   è ø€ ÒI sœ#˜cŸ(ÑIùr+  r%  )r  r%  rœ   r�   r  r¶   r·   rç   r›   )r¯   r  r  r  r¿   r¸   r  r§  Fzfailed on the image API)r¯   r  rÓ  rÌ  r¿   r¸   Úsuccessr   z)%s model %s %s; retrying with fallback %sz; image generation failed after trying all candidate models.r´  éÿÿÿÿrT   )r&  r¨  r¶  r  r  r  )r   r]  rw  rÙ   r^  r~  rŽ   r   rw   rž   r�  r}  rŠ   Ú_ATTRIBUTION_HEADERSÚ	enumeratere  rí   r`  rÈ  ÚpoprÚ  r  r}   Úinfor   )rf  r  r  rœ   rÛ  r  rÔ  rÀ   r¿   rˆ   Úmodel_chainrÓ  r…   r  rÌ  rÄ  r¸   Ú
last_errorÚir¯   rè   ÚoutcomerÖ  s                          r;   Úgeneratez&OpenRouterCompatImageProvider.generateï  sÆ  € ô
 ˜TŸZ™Z¨Ó6ˆð	dØ $× 1Ñ 1Ó 3ÑˆG�Xñ ™hÙØ�d—m‘m�_ð %Ø!Ÿ]™]˜OÐ+SðUà!ó#ð #ð
 ×/Ñ/°·
±
¸7Ó0CÓDˆÜ% lÓ3ˆà*0¯*©*Ð5GÓ*HÒ*NÈBÖO 3”c˜#•hÐOˆ
ÐOÙØ×Ñœc )›nÔ-Ø×ÑÑIÐ.BÒ.HÀbÔIÔIØ28À&Ñ)IÐ(JˆØÐ4Ô4Ð5ò 	RˆCÜ% cÓ*ˆDÚØ—‘¨À5È$À-ÑPÕQð	Rð # g¨g¨YÐ$7ÐPÔ;OÐPˆà/3ˆ
Ü$ [Ó1ò 	!‰KˆAˆxàˆGØ×'Ò'Ü)¨(°H¸gÀt×GWÑGWÓX�Ø˜(Ò"Ø×6Ñ6Ø%¨fÀfØ)°HÀgÐV\ð 7ó ^�ð 7>·k±kÀ,ÐPUÔ6VÑ2Ð\`‘à"&×"9Ñ"9Ø%¨f¸VÈWØ%¨wð #:ó #8‘�˜ð �{‰{˜9Ô%¨¨¸1ÄÀKÓ@PÐSTÑ@TÒ;TØ’Ü�K‰KØ;¸T¿Z¹ZÈÐSYÐ[fÐghÐklÑglÑ[môð !‰Jð'	!ð* ò ^œ^Ø—]‘]�OÐ#^Ð_Ø"¨T¯Z©ZÙ%0�+˜b’/°bÀÐV\ô^ð 	^øôY ò 	dÙÐ,¨T¯]©]¨O¸>È#ÈÐOÐQbÓcÕcûð	düò Ps#   ˜H5 ÂI$È5	I!È>IÉI!ÉI!)rg  rw   rh  rw   ri  rw   rë   rw   rj  rw   rk  úOptional[Dict[str, Any]]r[  r÷   r¼  ÚNone)r¼  rw   )r¼  zTuple[str, str])r¼  r÷   )r¼  r½  )r¼  úList[Dict[str, Any]])r”  rw   r•  rw   r–  r   r¼  rí  )r¼  úOptional[str])r¼  rë  rr   )rô   rî  r¼  rw   )rô   rî  r¼  z	list[str])r¯   rw   r  rw   r  rw   r  ú	List[str]r¿   rw   r¸   úDict[str, str]r  r½  r¼  r½  )r¯   rw   r  rw   rÓ  rw   rÌ  rí  r¿   rw   r¸   rð  r¼  z$Tuple[Dict[str, Any], Optional[str]])r  rw   r  rw   rœ   rî  rÛ  zOptional[List[str]]r  r   r¼  r½  )Ú__name__Ú
__module__Ú__qualname__Ú__doc__rl  Úpropertyr�   rh  rw  ry  r  r�  r—  r†  r‡  r�  rŸ  r¡  r~  rÈ  rÚ  r
   rê  r1   r=   r;   rZ  rZ  ö  s¥  „ ñ`ð
 `eñ6Ø #ð6Ø36ð6ØFIð6ØWZð6àð6à*Bð6àX\ð6ð 
ó6ð òó ðð òó ðó
óóSóó"ó _ó
aó
óHô6ô
*ðRNØðRNØ(+ðRNØ>AðRNØOXðRNàðRNà .ðRNà8FðRNð 
óRNðh/Øð/Ø(+ð/Ø58ð/ØCWð/àð/à .ð/ð 
.ó/ðd 0Dð7^à#'ÐUYñ7^Øð7^Ø),ð7^à ð7^à?Rð7^ð ð7^ð 
ô	7^r=   rZ  c                 ó\   — t        ddddddddddd	d
dœgdœ¬«      t        dddddd ¬«      gS )NÚ
openrouterÚ
OpenRouterÚOPENROUTER_IMAGE_MODELTzOpenRouter (image)ÚpaidzdGemini Flash Image, gpt-image-2, Krea 2, Qwen Image 3 & more via OpenRouter; uses OPENROUTER_API_KEYÚOPENROUTER_API_KEYzOpenRouter API keyzhttps://openrouter.ai/keys)r‘   r  r�   )r�   ÚbadgeÚtagÚenv_vars)rg  rh  ri  rë   rj  r[  rk  ÚnouszNous PortalÚNOUS_IMAGE_MODEL)rg  rh  ri  rë   rj  rk  )rZ  r1   r=   r;   Ú_build_providersr  )  s`   € ä%Ø&°\ÐP\Ø#Ð3KÐ`dà,ØØ}à/Ð;OÐXtñð ñ	ô
	ô 	&Ø ¨}È6Ð^dØ,¸4ô	Aðð r=   c                óD   — t        «       D ]  }| j                  |«       Œ y)z:Register the OpenRouter + Nous Portal image gen providers.N)r  Úregister_image_gen_provider)Úctxr¶  s     r;   Úregisterr  ?  s"   € ä$Ó&ò 2ˆØ×'Ñ'¨Õ1ñ2r=   )r   rw   r   rw   r:   r   r¼  r½  )r…   rw   r¼  rî  )r�   r   r‘   rw   r¼  r½  )r�   r   r‘   rw   r¼  z	List[Any])rŸ   r½  r¼  rï  )r   rw   r¯   rw   r°   rw   r±   rø   r²   rw   r¼  rî  )
r¿   rw   r†   rw   rÀ   rw   r¹   r   r¼  z List[Tuple[str, Dict[str, Any]]])r¿   rw   rÀ   rw   r†   rw   rÊ   rR   rË   rw   rÌ   r÷   r¼  rí  )r¿   rw   rÀ   rw   r¼  rÚ   )r¯   rw   r¼  r½  )
r¯   rw   r¿   rw   rÀ   rw   rë   rw   r¼  rw   )r�   rw   rô   r   rë   rw   r¼  r   )r’   r   r¼  zOptional[int])
rÿ   rw   rÊ   r½  rì   rî  r   rï  r¼  rî  )r�   rw   rô   r   rÊ   r½  rë   rw   r   rï  r  rî  r¼  rî  )r¯   rw   r  rw   r  rw   r  rï  rë   rw   r  r½  r¼  z Tuple[Dict[str, Any], List[str]])rÁ   r   r1  rw   r¼  rw   )rW   )r;  rî  r1  rw   r¼  rw   )r¯   rw   r¼  rw   )rÂ   r½  rE  rw   r¼  rî  )rŸ   r½  rU  rï  rV  rï  r   rï  r2  r   r¼  r½  )r¼  z#List[OpenRouterCompatImageProvider])r  r   r¼  rì  )[rô  Ú
__future__r   r‚   r¾   Úloggingr   rï   rÔ   Úpathlibr   Útypingr   r   r   r   r	   Úagent.image_gen_providerr
   r   r   r   r   r   r   Úplugins.image_gen._commonr   r   r   r   Ú	getLoggerrñ  r}   rœ  r®   r£  rƒ  rÒ  r}  r¿  r‹  rÉ   r’  rÈ   ró   rñ   rØ   rÖ   r!   Ú__annotations__Ú_GEMINI_RATIOSÚ_MAI_RATIOSÚ_KREA_RATIOSÚ_OPENAI_QUALITYr9   r<   rS   rã   rÚ   rþ   rV   r9  rÂ  rê   rT  r  r  râ  rŠ   r“   r—   r£   r´   rÃ   rÏ   rá   rå   rí   ré   rû   r  r  r#  r6  r<  rB  rI  rX  rZ  r  r  r1   r=   r;   ú<module>r     s£  ðòõ #ã Û Û Û Û 	Û Ý ß 3Õ 3÷&÷ &ñ &÷ jÓ ià	ˆ×	Ñ	˜8Ó	$€ð )€Ø-€Ø% Ð7Ð Ø  ! _°aÐ8€ð "°ÀFÑK€ØÐ ØÐ ð Ø+ØTñð Ø'ØIñð	Ð ð 0Ð Ø€Ø€Ø.Ð ð 0Ð à!Ð ð Ð ØKM€ÐHÓ Mð€ð J€ØB€Ø3€Ø¨"¸rÐRWÐafÑg€	ó`ñ +;Ø:ØEØ$°'ÀÈRô+Qñ &6Ø0ØDØ$Ð2KÐSTÐ_aô&cñ +ØØPØYØÐ,>ÈDÐXZÐegô	ñ  0Ø!ØGØ3ØÐ,MÐ[_Ø˜2ô ñ  0Ø!Ð#ZØ!¨°Qô 8ñ $4Ø%Ð'WØ!¨°Qô$8ñ (8Ø&ØKðð !¨°Aô(7ñ +ØÐOØ"°¸dÈ!ÐVWôYñ !1ØÐ`Ø"°¸dÈ!ÐVWô!Yñ .ØÐ]ØsØ  t°1¸qôBñQ,0Ð Ð,ó ,ñ^ ,¨B°À"ÈAÐXZÔ[Ð ñ $ò %ó Ð ð ^Ø\Øñ3Ð Ð/ó ð  e¸%ÈvÐdiØñÐ ñ  )Ò)[Ó\Ð ñ ˜}¨oÐ>Ó?Ð à]Ð ðeÐ ð ˜=Ñ*GÐHÈ6ÐSYÑ[fÐJgð€ð
 'àBØñ	Ð óIó(4ó
4ó
óXóð ØðØðØ*-ðØ5NðØY\ðàðð óó.ó(Eó
ó Hó	ð;Øð;Ø'ð;Ø1>ð;ØGPð;àó;ð6 #ñØ
ðØðØ$2ðØ@CðØLUðàðð óð&*Øð*Ø!ð*Ø47ð*ØENð*Ø\_ð*àð*ð &ó*óZ#ô@óQó
ðØðØ$-ðØ<EðØNWðØ_bðàóô(p^Ð$4ô p^óf	ô,2r=   