+
    jHàjog  ã                   ó�  a € R\ t20 t R t^ RIt^ RIt^ RIHtHtHtHtH	t	H
t
 ^ RIHt ^ RIHt ]P                  ! R4      t]! 4       t] ^ k R R ltRR	R
R	RR	RR	RR	RRRRRRRRRRRRRRRR/t]! 0 R]m4      t]! 0 R^m4      tR R ltR R ltR R ltR R  ltR!R"R#R$R%R&R'R(R)R(R*R+R,R-R.R/R0R1/	t] ^k 0 R_mtR2 R3 ltR4 R5 ltR6R7/R8 R9 llt R6R7/R: R; llt!R< R= lt"R`R> R? llt#R@ RA lt$RaRB RC llt%RD RE lt&RF RG lt'RH RI lt(RaRJ RK llt)RaRL RM llt*RN RO lt+RaRP RQ llt,RaRR RS llt-RaRT RU llt.RaRV RW llt/RaRX RY llt0RZ R[ lt1R# )ba²  Custom-provider entry normalization and per-route lookups (TLS, headers, context length, capabilities).

Split out of ``hermes_cli/config.py``; every name is re-imported there, so
``hermes_cli.config.<name>`` keeps resolving (and monkeypatching) as before. Functions that call
``get_compatible_custom_providers`` / ``load_config*`` import them lazily from ``hermes_cli.config``
so tests patching that module still intercept the call.
N)ÚAnyÚDictÚIteratorÚListÚOptionalÚTuple)Úurlparse)Únormalize_route_base_urlzhermes_cli.configc          
      óL   € V ^8„  d   QhR\         R\         R\         R\        RR/# )é   Úprovider_keyÚ	signatureÚmsgÚargsÚreturnN©Ústrr   )Úformats   "Ú@/home/ubuntu/.hermes/hermes-agent/hermes_cli/config_providers.pyÚ__annotate__r      s1   € ÷ ñ ¬#ð ¼#ð ÄCð ÔPSð ÐX\ñ ó    c                ó–   € T ;'       g    RV3pV\         9   d   R# \         P                  V4       \        P                  ! V.VO5!   R# )zKEmit ``logger.warning(msg, *args)`` at most once per (provider, signature).Ú?N)Ú_PROVIDER_NORMALIZE_WARNEDÚaddÚloggerÚwarning)r   r   r   r   Ú	dedup_keys   &&&* r   Ú_warn_once_per_providerr      s?   € à×$Ð$  iÐ0€IØÔ.Ô.ÙÜ×"Ñ" 9Ô-Ü
‡N‚N�3Ð˜Ör   ÚopenaiÚchat_completionsÚopenai_chatzopenai-chatzchat-completionsÚchatcompletionsÚ	responsesÚcodex_responsesÚopenai_responseszopenai-responsesÚ	anthropicÚanthropic_messageszanthropic-messagesÚmessagesÚbedrockÚbedrock_conversezbedrock-conversec                ó0   € V ^8„  d   QhR\         R\         /# )r   Úapi_moder   ©r   )r   s   "r   r   r   <   s   € ÷ ;ñ ;¤#ð ;¬#ñ ;r   c                ój   € V P                  4       p\        P                  VP                  4       V4      # )zUMap alias ``api_mode`` spellings to canonical transport names (unknown pass through).)ÚstripÚ_API_MODE_ALIASESÚgetÚlower)r,   Úcleaneds   & r   Ú_canonical_api_moder4   <   s'   € à�n‰nÓ€GÜ× Ñ  §¡£°'Ó:Ð:r   c                ó0   € V ^8„  d   QhR\         R\        /# ©r   Úvaluer   )r   r   )r   s   "r   r   r   B   s   € ÷ ñ œcð ¤cñ r   c                ó@   € V f   R# \        V 4      P                  4       # )z%Provider identity fields are strings.Ú )r   r/   )r7   s   &r   Úcoerce_provider_idr:   B   s   € à‚}ÙÜˆu‹:×ÑÓÐr   c                ó0   € V ^8„  d   QhR\         R\        /# )r   Ú	providersr   )r   Údict)r   s   "r   r   r   I   s   € ÷ 	ñ 	¤cð 	¬dñ 	r   c                óž   € \        V \        4      '       g   / # / pV P                  4        F  w  r#\        V4      pV'       g   K  W1V&   K   	  V# )zYCopy a ``providers:`` mapping so keys are strings (unquoted YAML ``2070:`` loads as int).)Ú
isinstancer=   Úitemsr:   )r<   ÚoutÚstoredr7   Úkeys   &    r   Ústringify_provider_maprD   I   sI   € ä�i¤×&Ò&Øˆ	Ø€CØ"Ÿ™Ö*‰ˆÜ  Ó(ˆß‰3Ø�‹Hñ +ð €Jr   c                ó–   € V ^8„  d   QhR\         R\         R\        \         \        \        \        \         3,          ,          3,          /# )r   r<   rC   r   )r   Útupler   r=   r   )r   s   "r   r   r   U   s9   € ÷ ñ ¤3ð ¬Sð ´U¼3ÄÌÌcÔSVÈhÍÕ@XÐ;XÕ5Yñ r   c                ó@  € \        V \        4      '       g   R# \        V4      pV'       g   R# V P                  V4      p\        V\        4      '       d   W#3# V P	                  4        F2  w  rE\        V4      V8X  g   K  \        V\        4      '       g   K/  WE3u # 	  R# )zXReturn ``(stored_key, entry)`` matching *key* by string identity (exact hit, then scan).©NN)r?   r=   r:   r1   r@   )r<   rC   ÚwantÚexactrB   Úentrys   &&    r   Úfind_provider_entryrL   U   s‡   € ä�i¤×&Ò&ØÐÜ˜cÓ"€DßØÐØ�M‰M˜$Ó€EÜ�%œ×ÒØˆ{ÐØ"Ÿ™Ö*‰ˆÜ˜fÓ%¨Ö-´*¸UÄD×2IÔ2IØ�=Ò ñ +ð Ðr   ÚapiKeyÚapi_keyÚbaseUrlÚbase_urlÚapiModer,   ÚkeyEnvÚkey_envÚ	apiKeyEnvÚdefaultModelÚdefault_modelÚcontextLengthÚcontext_lengthÚrateLimitDelayÚrate_limit_delayÚsessionAffinityHeaderÚsession_affinity_headerc                ó^   € V ^8„  d   QhR\         \        \        3,          R\        R\        /# ©r   rK   r   r   ©r=   r   r   )r   s   "r   r   r   }   s)   € ÷ ñ ¤4¬¬S¨¥>ð Äð Ìñ r   c                óØ  € R FÐ  pV P                  V4      p\        V\        4      '       d   VP                  4       '       g   KB  VP                  4       p\        P
                  ! RV4      '       d   Vu #  \        V4      pV'       d)   VP                  '       d   VP                  '       d   Vu # \        P                  RT;'       g    RW$4       KÒ  	  R#   \         d    Rp Lfi ; i)zéFirst usable URL among ``base_url``/``url``/``api``, or "".

URLs with unresolved ``${ENV_VAR}`` / ``{region}`` placeholders are accepted unvalidated: they
expand at runtime, and rejecting them here would silently drop the provider.
z	\{[^}]+\}NuP   providers.%s: '%s' value '%s' is not a valid URL (no scheme or host) â€” skippedr   r9   )rP   ÚurlÚapi)r1   r?   r   r/   ÚreÚsearchr   Ú
ValueErrorÚschemeÚnetlocr   r   )rK   r   Úurl_keyÚraw_urlÚ	candidateÚparseds   &&    r   Ú_pick_provider_base_urlrl   }   s½   € ó .ˆØ—)‘)˜GÓ$ˆÜ˜7¤C×(Ò(¨W¯]©]¯_ª_ÙØ—M‘M“Oˆ	ô
 �9Š9�\ 9×-Ò-ØÒð	Ü˜iÓ(ˆF÷ �f—m—m�m¨¯¯¨ØÒÜ�‰ð.à×Ð˜C ö	5ñ# .ñ* øô ô 	ØŠFð	ús   Á7CÃC)Ã(C)c                ót   € V ^8„  d   QhR\         R\        \        \        \         3,          \        3,          /# )r   Úmodelsr   )r   rF   r=   r   Úbool)r   s   "r   r   r   ›   s,   € ÷ ñ ¤sð ¬u´T¼#¼s¸(µ^ÄTÐ5IÕ/Jñ r   c                óH  € Rp\        V \        4      '       dA   V '       d9   \        V 4      pVP                  RR4      RJ d   RpVP                  RR4       W!3# \        V \        4      '       Ed+   V '       Ed"   / pV  EF  p\        V\        4      '       d+   VP                  4       '       d   / W4P                  4       &   KD  \        V\        4      '       g   K\  VP                  R4      p\        V\        4      '       d   VP                  4       '       g   VP                  R4      p\        V\        4      '       d   VP                  4       '       g   KØ  VP                  4        UUu/ uF  w  rgVR9  g   K  WgbK  	  uppW5P                  4       &   EK  	  W13# / V3# u uppi )	zþNormalize an entry's ``models`` to ``(models_dict, discovered_flag)``.

The legacy in-mapping ``__discovered_model_catalog__`` sentinel is accepted and stripped; a
plain list of ids or ``[{id: ...}]`` rows is converted so /model doesn't show (0) models.
FÚ__discovered_model_catalog__NTÚ__explicit_model_allowlist__ÚidÚname>   rs   rt   )r?   r=   ÚpopÚlistr   r/   r1   r@   )rn   Ú
discoveredÚmodels_copyÚnormalized_modelsÚitemÚmodel_idÚkÚvs   &       r   Ú_normalize_provider_modelsr~   ›   sR  € ð €JÜ�&œ$×Ò§Fô ˜6“lˆØ�?‰?Ð9¸4Ó@ÀDÓHØˆJØ�‰Ð6¸Ô=ØÐ&Ð&Ü�&œ$×Ó§F FØ,.ÐÜˆDÜ˜$¤×$Ò$¨¯©¯ªØ24Ð!§*¡*£,Ñ/ÙÜ˜d¤D×)Ò)ÙØ—x‘x “~ˆHÜ˜h¬×,Ò,°H·N±N×4DÒ4DØŸ8™8 FÓ+�Ü˜h¬×,Ò,°H·N±N×4DÒ4DÙà!%§¡¤ô3JÙ!-™˜°¸.Ñ1H”�’¡ò3JÐŸn™nÓ.Ô/ñ ð !Ð,Ð,Øˆzˆ>Ðùó3Js   Å(FÅ8Fr   r9   c          	      ót   € V ^8„  d   QhR\         R\        R\        \        \        \         3,          ,          /# r^   ©r   r   r   r=   )r   s   "r   r   r   ½   s6   € ÷ ]ñ ]Üð]Ü!$ð]Ü.6´t¼CÄ¸Hµ~Õ.Fñ]r   c               ó   a a€ \        S \        4      '       g   R# \        S 4      o \        V4      pRS 9   d   RS 9  d   S R,          S R&   \        P	                  4        F?  w  r#VS 9   g   K  VS 9  g   K  \        TRV 2RT;'       g    RW#4       S V,          S V&   KA  	  \        S P                  4       4      \        ,
          \        \        P                  4       4      ,
          pV'       dQ   \        TRRP                  \        V4      4      ,           R	T;'       g    RR
P                  \        V4      4      4       \        S V4      p\        S P                  R4      4      ;'       g    TpV'       d	   V'       g   R# RVRV/oV'       d   VSR&   R V 3R llpR V3R llpV! RV! R4      4       V! RV! R4      4       V! RR4      p	V! RV	4       V	'       d4   S P                  R4      '       d   S P                  R4      '       g   V	SR&   V! RR4      p
T! RV
'       d   \        V
4      MR4       V! RV! RR4      4       V! RV! R4      4       \        S P                  R4      4      w  r¼V! RV4       S P                  R4      RJ g	   V'       d   RSR&   S P                  R4      p\        V\        4      '       d\   T! RVP	                  4        UUu/ uF7  w  rï\        V\        4      '       g   K  \        V\         4      '       g   K5  WïbK9  	  upp4       RR 3R R! 3R"R# 33 F1  w  ppV! S P                  V4      4      '       g   K%  S V,          SV&   K3  	  \        S P                  R$4      \        4      '       d   \        S R$,          4      SR$&   V! R%\#        S P                  R%4      4      4       V! R&V! R&4      4       V! R'V! R'4      4       S P                  R(4      p\        V\         4      '       d   VSR(&   S# \        V\        4      '       d*   VP%                  4       '       d   VP%                  4       SR(&   S# u uppi ))z>Return a runtime-compatible custom provider entry or ``None``.NÚapi_key_envrS   zcamel:z[providers.%s: camelCase key '%s' auto-mapped to '%s' (use snake_case to avoid this warning)r   zunknown:Ú,z-providers.%s: unknown config keys ignored: %sz, rt   rP   r   c                ó0   € V ^8„  d   QhR\         R\         /# )r   Úkeysr   r-   )r   s   "r   r   Ú6_normalize_custom_provider_entry.<locals>.__annotate__á   s   € ÷ ;ñ ;œð ;¤ñ ;r   c                  ó    <€ R pV  F  pSP                  V4      pV'       g   K   M	  \        V\        4      '       d   VP                  4       # R# )Nr9   )r1   r?   r   r/   )r…   Úvalr|   rK   s   *  €r   Ú	_strippedÚ3_normalize_custom_provider_entry.<locals>._strippedá   sF   ø€ ØˆÛˆAØ—)‘)˜A“,ˆCß‰sÙñ ô )¨¬c×2Ò2ˆs�y‰y‹{Ð:¸Ð:r   c                ó4   € V ^8„  d   QhR\         R\        RR/# )r   Úfieldr7   r   Nr   )r   s   "r   r   r†   é   s!   € ÷ &ñ &”Cð &¤ð &¨ñ &r   c                 ó&   <€ V'       d   VSV &   R # R # ©N© )rŒ   r7   Ú
normalizeds   &&€r   Ú_putÚ._normalize_custom_provider_entry.<locals>._puté   s   ø€ ßØ %ˆJ�uÓñ r   rN   Úkey_cmdr,   Ú	transportr9   ÚmodelrV   Úcatalog_providerrn   Úmodels_discoveredTÚcapabilitiesrX   c                 ó<   € \        V \        4      ;'       d    V ^ 8„  # ©é    )r?   Úint©r}   s   &r   Ú<lambda>Ú2_normalize_custom_provider_entry.<locals>.<lambda>  s   € ¤Z°´3Ó%7×%AÐ%A¸AÀ¹EÐ%Ar   rZ   c                 óH   € \        V \        \        34      ;'       d    V ^ 8¬  # rš   )r?   rœ   Úfloatr�   s   &r   rž   rŸ     s   € ¤z°!´c¼5°\Ó'B×'MÐ'MÀqÈAÁvÐ'Mr   Údiscover_modelsc                 ó.   € \        V \        \        34      # rŽ   )r?   ro   r   r�   s   &r   rž   rŸ     s   € ¤j°´T¼3°KÔ&@r   Ú
extra_bodyÚextra_headersr\   Ússl_ca_certÚ
ssl_verify)r?   r=   r:   Ú_CAMEL_ALIASESr@   r   Úsetr…   Ú_KNOWN_PROVIDER_KEYSÚjoinÚsortedrl   r1   r4   r~   r   ro   Únormalize_extra_headersr/   )rK   r   ÚcamelÚsnakeÚunknownrP   rt   r‰   r‘   rS   r,   Úmodels_dictrw   r˜   rC   r7   rŒ   Úokr§   r�   s   f$                 @r   Ú _normalize_custom_provider_entryr³   ½   sØ  ù€ ô �eœT×"Ò"Ùô �‹K€EÜ% lÓ3€Là˜Ô )°5Ô"8Ø  Õ/ˆˆiÑÜ&×,Ñ,Ö.‰ˆØ�EŽ>˜e¨5Ö0Ü#Ø  u gÐ.ð9à×#Ð#  Uô	3ð
 ! �<ˆE�%‹Lñ /ô �%—*‘*“,ÓÔ"6Õ6¼¼^×=PÑ=PÓ=RÓ9SÕS€GßÜØ˜* s§x¡x´°w³Ó'@Õ@Ø;Ø×Ð˜C §¡¬6°'«?Ó!;ô	=ô
 ' u¨lÓ;€HÜ˜eŸi™i¨Ó/Ó0×@Ð@°L€DßŸ4ÙØ"(¨$°
¸HÐ!E€JßØ%1ˆ
�>Ñ"÷;ð ;÷&ð &ñ 	ˆ‘I˜iÓ(Ô)Ùˆ‘I˜iÓ(Ô)Ù˜	 =Ó1€GÙˆ�GÔß�5—9‘9˜]×+Ò+°E·I±I¸i×4HÒ4HØ$+ˆ
�=Ñ!Ù˜ [Ó1€HÙˆ·hÔ(¨Ô2ÀBÔGÙˆ‘)˜G _Ó5Ô6áÐ	™YÐ'9Ó:Ô;ô 9¸¿¹À8Ó9LÓMÑ€KÙˆ�;ÔØ‡y�yÐ$Ó%¨Ó-·Ø*.ˆ
Ð&Ñ'à—9‘9˜^Ó,€LÜ�,¤×%Ò%Ùˆ^Ø)5×);Ñ);Ô)=ôAÙ)=™:˜3Ü˜#œs×#ô Ü(2°5¼$×(?ô ˆCŠJÑ)=òAô 	Bð
 
ÑAÐBØ	ÑMÐNØ	Ñ@ÐAó‰	ˆˆrñ
 ˆe�i‰i˜Ó×ÔØ % e¥ˆJ�uÓñô �%—)‘)˜LÓ)¬4×0Ò0Ü#'¨¨lÕ(;Ó#<ˆ
�<Ñ ñ 	ˆÔ1°%·)±)¸OÓ2LÓMÔNÙÐ	"¡IÐ.GÓ$HÔIÙˆ™	 -Ó0Ô1à—‘˜<Ó(€JÜ�*œd×#Ò#Ø#-ˆ
�<Ñ ð Ðô 
�J¤×	$Ò	$¨×)9Ñ)9×);Ò);Ø#-×#3Ñ#3Ó#5ˆ
�<Ñ àÐùó3As   ËQ
Ë9Q
ÌQ
c          	      ót   € V ^8„  d   QhR\         R\        R\        \        \        \         3,          ,          /# r^   r€   )r   s   "r   r   r     s1   € ÷ ñ ÜðÜ!$ðÜ.6´t¼CÄ¸Hµ~Õ.Fñr   c               óÂ   € \        WR7      pVf   R# RVR,          /pR	 F  pWB9   g   K  W$,          W4&   K  	  RV9   d   VR,          VR&   RV9   d   VR,          VR&   V# )
zDTranslate a legacy custom provider entry to the v12 providers shape.©r   Nrb   rP   r•   rV   r,   r”   )rt   rN   rS   r“   rn   r—   rX   rZ   r¢   r¤   r¥   r\   r¦   r§   r–   )r³   )rK   r   r�   Úprovider_entryrŒ   s   &$   r   Ú)_custom_provider_entry_to_provider_configr¸     s}   € ô 2°%ÔS€JØÒÙà&+¨Z¸
Õ-CÐ%D€NóTˆð ÖØ$.Õ$5ˆNÓ!ñTð �*ÔØ*4°WÕ*=ˆ�Ñ'Ø�ZÔØ&0°Õ&<ˆ�{Ñ#ØÐr   c                óh   € V ^8„  d   QhR\         R\        \        \        \         3,          ,          /# )r   Úproviders_dictr   )r   rv   r=   r   )r   s   "r   r   r   2  s'   € ÷ ñ ´sð ¼tÄDÌÌcÈÅNÕ?Sñ r   c                ó  € \        V \        4      '       g   . # . pV P                  4        F[  w  r#\        V\        4      '       d   \        V4      '       g   K.  \	        V\        V4      R7      pVf   KJ  VP                  V4       K]  	  V# )zUNormalize enabled ``providers`` config entries into the legacy custom-provider shape.r¶   )r?   r=   r@   Úis_provider_enabledr³   r:   Úappend)rº   Úcustom_providersrC   rK   r�   s   &    r   Ú"providers_dict_to_custom_providersr¿   2  sy   € ä�n¤d×+Ò+Øˆ	Ø-/ÐØ$×*Ñ*Ö,‰
ˆÜ�eœT×"Ò"Ô+>¸u×+EÒ+EÙÜ5°eÔJ\Ð]`ÓJaÔbˆ
ØÔ!Ø×#Ñ# JÖ/ñ -ð Ðr   c                ó    € V ^8„  d   QhR\         \        \        \        3,          ,          R\        \        \        \        3,          ,          /# )r   Úconfigr   )r   r=   r   r   rv   )r   s   "r   r   r   @  s6   € ÷ -ñ -Ü”Tœ#œs˜(•^Õ$ð-Ü04´T¼#¼s¸(µ^Õ0Dñ-r   c                ó†  € ^ RI Hp V f   V! 4       p V P                  R4      pVeB   \        V\        4      '       g,   \
        P                  R\        V4      P                  4       . pT;'       g    .  Uu. uF  p\        V4      NK  	  ppV\        V P                  R4      4      ,          pR R lp. p\        4       p\        4       pV Fí  p	V	f   K	  V! V	R4      p
V! V	R4      p\        V	P                  R	R
4      ;'       g    R
4      P                  4       P                  R4      P                  4       pW¼V! V	R4      3pV
'       d	   W§9   d   K†  V'       d   V'       d	   WØ9   d   Kž  VP!                  V	4       V
'       d   VP#                  V
4       V'       g   KÒ  V'       g   KÜ  VP#                  V4       Kï  	  V# u upi )zŸDeduplicated list view over legacy ``custom_providers`` and v12+ ``providers``.

Never materialised back into config.yaml (it would duplicate entries in UIs).
)Úload_configr¾   už   custom_providers is a %s, expected a list â€” skipping legacy entries; 'providers:' entries are still used. Move provider configs to the 'providers:' section.r<   c                ó^   € V ^8„  d   QhR\         \        \        3,          R\        R\        /# )r   rK   rŒ   r   r_   )r   s   "r   r   Ú5get_compatible_custom_providers.<locals>.__annotate__W  s)   € ÷ ?ñ ?”Tœ#œs˜(•^ð ?¬Cð ?´Cñ ?r   c                 ó„   € \        V P                  VR 4      ;'       g    R 4      P                  4       P                  4       # )r9   )r   r1   r/   r2   )rK   rŒ   s   &&r   Ú_normÚ.get_compatible_custom_providers.<locals>._normW  s2   € Ü�5—9‘9˜U BÓ'×-Ð-¨2Ó.×4Ñ4Ó6×<Ñ<Ó>Ð>r   r   rt   rP   r9   Ú/r•   )Úhermes_cli.configrÃ   r1   r?   rv   r   r   ÚtypeÚ__name__r³   r¿   r©   r   r/   Úrstripr2   r½   r   )rÁ   rÃ   r¾   ÚeÚ
candidatesrÇ   Ú
compatibleÚseen_provider_keysÚseen_name_url_pairsrK   r   rt   rP   Úpairs   &             r   Úget_compatible_custom_providersrÔ   @  s�  € õ .Ø‚~Ù“ˆà—z‘zÐ"4Ó5ÐØÒ#¬JÐ7GÌ×,NÒ,Nô 	�‰ðfäÐ!Ó"×+Ñ+ô	-ð ÐØ@P×@VÐ@VÐTVÐ@VÓXÑ@V¸!Ô2°1Ö5Ñ@V€JÐXØÔ4°V·Z±ZÀÓ5LÓMÕM€Jõ?ð (*€JÜ!›eÐÜ"›uÐÛˆØŠ=ÙÙ˜U NÓ3ˆÙ�U˜FÓ#ˆÜ�u—y‘y ¨RÓ0×6Ð6°BÓ7×=Ñ=Ó?×FÑFÀsÓK×QÑQÓSˆØ¡ e¨WÓ 5Ð6ˆß˜LÔ>Ùß—H Ô!<ÙØ×Ñ˜%Ô ßØ×"Ñ" <Ô0ß‰4—H‘HØ×#Ñ# DÖ)ñ ð  Ðùò3 Ys   Á6F>c          	      óÂ   € V ^8„  d   QhR\         R\        \        \        \         \        3,          ,          ,          R\        \        \         \        3,          ,          /# )r   rP   r¾   rÁ   ©r   r   rv   r=   r   )r   s   "r   r   r   p  sE   € ÷ ñ Üðäœt¤D¬¬c¨¥NÕ3Õ4ðô ”Tœ#œs˜(•^Õ$ñr   c              #  óf  "  € ^ RI Hp Vf
    V! V4      pV '       d   \        V\        4      '       g   R# \        V 4      pV'       g   R# V FK  p\        V\        4      '       g   K  \        VP                  R4      4      pV'       g   K?  Wd8X  g   KG  Vx € KM  	  R#   \         d    . p L—i ; i5i)už   Yield entries whose normalized route identity equals *base_url*.

None *custom_providers* â†’ ``get_compatible_custom_providers(config)`` (failure â†’ none).
)rÔ   NrP   )rÊ   rÔ   Ú	Exceptionr?   rv   r	   r=   r1   )rP   r¾   rÁ   rÔ   Ú
target_urlrK   Ú	entry_urls   &&&    r   Ú_entries_for_routerÛ   p  s˜   é € õ BØÒð	"Ù>¸vÓFÐ÷ œ:Ð&6¼×=Ò=ÙÜ)¨(Ó3€JßÙÛ!ˆÜ˜%¤×&Ò&ÙÜ,¨U¯Y©Y°zÓ-BÓCˆ	ß‰9˜Ö0ØŒKó "øô ô 	"Ø!Òð	"üs9   ‚B1ŽB –B1žA)B1ÂB1Â
B1ÂB.Â+B1Â-B.Â.B1c          	      óÎ   € V ^8„  d   QhR\         R\        \        \        \         \        3,          ,          ,          R\        \        \         \        3,          ,          R\         /# ©r   rP   r¾   rÁ   r   rÖ   )r   s   "r   r   r   ‹  sO   € ÷ ñ Üðäœt¤D¬¬c¨¥NÕ3Õ4ðô ”Tœ#œs˜(•^Õ$ðô 	ñ	r   c                óÚ   € \        WV4       FZ  pR FQ  pVP                  V4      p\        V\        4      '       g   K,  VP	                  4       '       g   KD  \        V4      u u # 	  K\  	  R# )a>  Canonical ``api_mode`` of the first custom entry serving *base_url*, or ``""``.

Route identity is the URL, not the host: a Codex proxy on ``127.0.0.1`` declares its wire
protocol here and nowhere else, so metadata lookups keyed on the transport read it from the
entry instead of guessing from the hostname (#116191).
r9   )r,   r”   )rÛ   r1   r?   r   r/   r4   )rP   r¾   rÁ   rK   rŒ   r7   s   &&&   r   Úget_custom_provider_api_moderß   ‹  sU   € ô $ HÀÖGˆÛ.ˆEØ—I‘I˜eÓ$ˆEÜ˜%¤×%Ô%¨%¯+©+¯-¬-Ü*¨5Ó1Ô1ó /ñ Hñ
 r   c          	      ó–   € V ^8„  d   QhR\         \        \        3,          R\        R\        \         \        \        3,          ,          /# )r   rK   r•   r   )r=   r   r   r   )r   s   "r   r   r   ž  s6   € ÷ >ñ >œD¤¤c �Nð >´3ð >¼8ÄDÌÌcÈÅNÕ;Sñ >r   c                óª   € V P                  R4      p\        V\        4      '       g   R# VP                  V4      p\        V\        4      '       d   V# R# )zAReturn ``entry.models[model]`` when both are mappings, else None.rn   N)r1   r?   r=   )rK   r•   rn   Ú	model_cfgs   &&  r   Ú_route_model_cfgrã   ž  sE   € à�Y‰Y�xÓ €FÜ�fœd×#Ò#ÙØ—
‘
˜5Ó!€IÜ" 9¬d×3Ò3ˆ9Ð=¸Ð=r   c                ó  € V ^8„  d   QhR\         R\         R\        \        \        \         \        3,          ,          ,          R\        \        \         \        3,          ,          R\
        \        \         \        3,          ,          /# ©r   r•   rP   r¾   rÁ   r   )r   r   rv   r=   r   r   )r   s   "r   r   r   §  sf   € ÷ 	ñ 	Üð	äð	ô œt¤D¬¬c¨¥NÕ3Õ4ð	ô ”Tœ#œs˜(•^Õ$ð		ô *2´$´s¼C°xµ.Õ)Añ		r   c              #  ó^   "  € \        WV4       F  p\        W@4      pVf   K  Vx € K  	  R# 5i)zHYield the ``models.<model>`` mapping of every entry matching *base_url*.N)rÛ   rã   )r•   rP   r¾   rÁ   rK   râ   s   &&&&  r   Ú_route_model_cfgsrç   §  s.   é € ô $ HÀÖGˆÜ$ UÓ2ˆ	ØÔ ØŒOó Hùs   ‚-£
-c                óF   € V ^8„  d   QhR\         R\        \        ,          /# r6   )r   r   ro   )r   s   "r   r   r   ³  s   € ÷ ñ œcð ¤h¬t¥nñ r   c                 óâ   € V f   R # \        V \        4      '       d   V # \        V \        4      '       d;   V P                  4       P	                  4       pV\
        9   d   R# V\        9   d   R# R # R # )NFT)r?   ro   r   r/   r2   Ú_FALSE_WORDSÚ_TRUE_WORDS)r7   Úlowereds   & r   Ú_coerce_ssl_verifyrí   ³  s_   € Ø‚}ÙÜ�%œ×ÒØˆÜ�%œ×ÒØ—+‘+“-×%Ñ%Ó'ˆØ¤<Ô/ˆuÐ]¸WÌÔ=S°TÐ]ÐY]Ð]Ùr   c          
      óð   € V ^8„  d   QhR\         R\        \        \        \         \        3,          ,          ,          R\        \        \         \        3,          ,          R\        \         \        3,          /# rÝ   rÖ   )r   s   "r   r   r   ¾  sW   € ÷ ñ Üðäœt¤D¬¬c¨¥NÕ3Õ4ðô ”Tœ#œs˜(•^Õ$ðô 15´S¼#°Xµñr   c                ó  € \        WV4       Fy  p/ pVP                  R4      p\        V\        4      '       d*   VP	                  4       '       d   VP	                  4       VR&   \        VP                  R4      4      pVe   WdR&   Vu # 	  / # )zOReturn TLS settings from a matching ``custom_providers`` / ``providers`` entry.r¦   r§   )rÛ   r1   r?   r   r/   rí   )rP   r¾   rÁ   rK   rA   ÚcaÚverifys   &&&    r   Ú get_custom_provider_tls_settingsrò   ¾  s}   € ô
 $ HÀÖGˆØ ˆØ�Y‰Y�}Ó%ˆÜ�bœ#×Ò 2§8¡8§:¢:Ø!#§¡£ˆC�ÑÜ# E§I¡I¨lÓ$;Ó<ˆØÒØ &�ÑØŠ
ñ Hð €Ir   c                óô   € V ^8„  d   QhR\         \        \        3,          R\        R\        \        \         \        \        3,          ,          ,          R\        \         \        \        3,          ,          RR/# ©r   Úclient_kwargsrP   r¾   rÁ   r   N©r=   r   r   r   rv   )r   s   "r   r   r   Ï  sa   € ÷ 
8ñ 
8ÜœœS˜•>ð
8äð
8ô œt¤D¬¬c¨¥NÕ3Õ4ð
8ô ”Tœ#œs˜(•^Õ$ð	
8ð 15ñ	
8r   c                óŽ   € \        WV4      pVP                  R4      '       d   VR,          V R&   RV9   d   VR,          V R&   R# R# )zCAttach per-provider TLS knobs to OpenAI client kwargs when matched.r¦   r§   N)rò   r1   )rõ   rP   r¾   rÁ   Útlss   &&&& r   Ú*apply_custom_provider_tls_to_client_kwargsrù   Ï  sJ   € ô +¨8ÀvÓ
N€CØ
‡w�wˆ}×ÒØ'*¨=Õ'9ˆ�mÑ$Ø�sÔØ&)¨,Õ&7ˆ�lÓ#ñ r   c                óR   € V ^8„  d   QhR\         R\        \        \        3,          /# )r   r¥   r   )r   r=   r   )r   s   "r   r   r   Ü  s&   € ÷ Oñ O¬3ð O´4¼¼S¸µ>ñ Or   c                óÈ   € \        V \        4      '       d	   V '       g   / # V P                  4        UUu/ uF   w  rVf   K  \        V4      \        V4      bK"  	  upp# u uppi )zëNormalize a raw ``extra_headers`` value into a ``dict[str, str]``.

SECURITY: header values routinely carry credentials (Cloudflare Access service tokens, proxy
auth, custom bearer schemes). Callers must never log the returned values.
)r?   r=   r@   r   )r¥   r|   r}   s   &  r   r­   r­   Ü  sM   € ô �m¤T×*Ò*·-Øˆ	Ø'4×':Ñ':Ô'<ÔNÑ'<™t˜qÀŒNŒC�‹F”C˜“FŠNÑ'<ÒNÐNùÓNs   ´AÁAc          
      óð   € V ^8„  d   QhR\         R\        \        \        \         \        3,          ,          ,          R\        \        \         \        3,          ,          R\        \         \         3,          /# rÝ   rÖ   )r   s   "r   r   r   ç  sW   € ÷ 
ñ 
Üð
äœt¤D¬¬c¨¥NÕ3Õ4ð
ô ”Tœ#œs˜(•^Õ$ð
ô 15´S¼#°Xµñ
r   c                óx   € \        WV4       F)  p\        VP                  R4      4      pV'       g   K'  Vu # 	  / # )u—   ``extra_headers`` of the first route-matching entry declaring any, else ``{}``.
SECURITY: values may carry credentials â€” callers must never log them.r¥   )rÛ   r­   r1   )rP   r¾   rÁ   rK   Úheaderss   &&&  r   Ú!get_custom_provider_extra_headersrÿ   ç  s:   € ô $ HÀÖGˆÜ)¨%¯)©)°OÓ*DÓEˆß‰7ØŠNñ Hð €Ir   c                óô   € V ^8„  d   QhR\         \        \        3,          R\        R\        \        \         \        \        3,          ,          ,          R\        \         \        \        3,          ,          RR/# rô   rö   )r   s   "r   r   r   ô  sa   € ÷ .ñ .ÜœœS˜•>ð.äð.ô œt¤D¬¬c¨¥NÕ3Õ4ð.ô ”Tœ#œs˜(•^Õ$ð	.ð 15ñ	.r   c                ó¤   € \        WV4      pV'       g   R# \        V P                  R4      ;'       g    / 4      pVP                  V4       WPR&   R# )z¶Merge per-provider ``extra_headers`` onto OpenAI client ``default_headers`` (provider wins
over SDK defaults, most specific level). SECURITY: values may carry credentials; never log.NÚdefault_headers)rÿ   r=   r1   Úupdate)rõ   rP   r¾   rÁ   r¥   Úmergeds   &&&&  r   Ú4apply_custom_provider_extra_headers_to_client_kwargsr  ô  sJ   € ô 6°hÐRXÓY€MßÙÜ�-×#Ñ#Ð$5Ó6×<Ð<¸"Ó=€FØ
‡M�M�-Ô Ø'-Ð#Ó$r   c          	      óÎ   € V ^8„  d   QhR\         R\        \        \        \         \        3,          ,          ,          R\        \        \         \        3,          ,          R\         /# rÝ   rÖ   )r   s   "r   r   r     sO   € ÷ ñ Üðäœt¤D¬¬c¨¥NÕ3Õ4ðô ”Tœ#œs˜(•^Õ$ðô 14ñr   c                óÎ   € \        WV4       FT  pVP                  R4      p\        V\        4      '       g   K,  VP	                  4       '       g   KD  VP	                  4       u # 	  R# )zØHeader NAME declared as ``session_affinity_header`` on the route-matching entry, else "".

Opt-in per provider (default off): Hermes never ships a session identifier to an endpoint
that did not ask for one (#86241).
r\   r9   )rÛ   r1   r?   r   r/   )rP   r¾   rÁ   rK   Úheaders   &&&  r   Ú+get_custom_provider_session_affinity_headerr	    sM   € ô $ HÀÖGˆØ—‘Ð4Ó5ˆÜ�fœc×"Ô" v§|¡|§~¤~Ø—<‘<“>Ò!ñ Hñ r   c                óð   € V ^8„  d   QhR\         R\         R\        \        \        \         \        3,          ,          ,          R\        \        \         \        3,          ,          R\        \
        ,          /# rå   )r   r   rv   r=   r   rœ   )r   s   "r   r   r     s]   € ÷ *ñ *Üð*äð*ô œt¤D¬¬c¨¥NÕ3Õ4ð*ô ”Tœ#œs˜(•^Õ$ð	*ô 19¼µñ	*r   c                óÄ  € ^ RI HpHp V '       d	   V'       g   R# Vf    T! Vf   V! 4       MT4      pR R lp\        WW#4       F"  pV! VP	                  R4      4      p	V	f   K   V	u # 	  \        WV4       F"  p
V! V
P	                  R4      4      p	V	f   K   V	u # 	  R#   \         d6    Tf    R# TP	                  R4      p\        T\        4      '       d   TM. p L«i ; i)a  Per-model ``context_length`` override from a route-matching entry, or ``None``.

Before this helper existed, the lookup was duplicated in ``run_agent.py``'s startup path only; every
other path (notably ``/model`` switch) fell back to the 128K default. See #15779.
©rÔ   Úload_config_readonlyNr¾   c                óF   € V ^8„  d   QhR\         R\        \        ,          /# )r   Úrawr   )r   r   rœ   )r   s   "r   r   Ú8get_custom_provider_context_length.<locals>.__annotate__+  s   € ÷ (ñ (œ3ð (¤8¬C¥=ñ (r   c                 ó`   €  \        V 4      pT^ 8”  d   T# R #   \        \        3 d     R # i ; irŽ   )rœ   Ú	TypeErrorre   )r  Úctxs   & r   Ú_positive_intÚ9get_custom_provider_context_length.<locals>._positive_int+  s<   € ð	Ü�c“(ˆCð ˜A”gˆsÐ' 4Ð'øô œ:Ð&ô 	Úð	ús   ‚ ˜-¬-rX   )	rÊ   rÔ   r  rØ   r1   r?   rv   rç   rÛ   )r•   rP   r¾   rÁ   rÔ   r  r  r  râ   r  rK   s   &&&&       r   Ú"get_custom_provider_context_lengthr    sã   € ÷ XßŸÙØÒð	Dñ  ?ÐY_ÒYgÑ?SÔ?UÐmsÓtÐõ(ô ' uÐ8HÖQˆ	Ù˜IŸM™MÐ*:Ó;Ó<ˆØŒ?ØŠJñ Rô $ HÀÖGˆÙ˜EŸI™IÐ&6Ó7Ó8ˆØŒ?ØŠJñ Hñ øô1 ô 	DØŠ~ÚØ—*‘*Ð/Ó0ˆCÜ&0°´d×&;Ò&;™sÀÒð		Dús    B ÂCÂ1+CÃCc                óü   € V ^8„  d   QhR\         R\         R\         R\        \        \        \         \        3,          ,          ,          R\        \        \         \        3,          ,          R\        \
        ,          /# )r   r•   rP   Ú
capabilityr¾   rÁ   r   )r   r   rv   r=   r   ro   )r   s   "r   r   r   @  sg   € ÷ ñ Üðäðô ðô œt¤D¬¬c¨¥NÕ3Õ4ð	ô
 ”Tœ#œs˜(•^Õ$ðô
 19¼µñr   c                ó  € ^ RI HpHp V '       d   V'       d	   V'       g   R# Vf    Vf   V! 4       pV! V4      p\	        WW44       F.  pVP                  V4      p\        V\        4      '       g   K,  Vu # 	  R#   \         d     R# i ; i)z¤Explicit boolean capability for one custom-provider model, or ``None``. Scoped to the
normalized route + exact runtime model id so aliases can declare capabilities.r  N)rÊ   rÔ   r  rØ   rç   r1   r?   ro   )	r•   rP   r  r¾   rÁ   rÔ   r  râ   r7   s	   &&&&&    r   Ú$get_custom_provider_model_capabilityr  @  s…   € ÷ XßŸ¯
ÙØÒð	ØŠ~ñ .Ó/�Ù>¸vÓFÐô ' uÐ8HÖQˆ	Ø—‘˜jÓ)ˆÜ�eœT×"Ô"ØŠLñ Rñ øô ô 	Úð	ús   ¨A; Á;B
Â	B
c                óh   € V ^8„  d   QhR\         \        \        \        3,          ,          R\        /# )r   Úprovider_cfgr   )r   r=   r   r   ro   )r   s   "r   r   r   \  s'   € ÷ ñ ¤h¬t´C¼°H­~Õ&>ð Ä4ñ r   c                ó  € \        V \        4      '       g   R# V P                  RR4      p\        V\        4      '       d   V# \        V\        4      '       d&   VP                  4       P                  4       \        9  # \        V4      # )z¦Whether a ``providers.<name>`` block is enabled: default True; only an explicit
``enabled: false`` hides it from the picker, ``/models``, runtime resolver and doctor.TÚenabled)r?   r=   r1   ro   r   r/   r2   rê   )r  Úflags   & r   r¼   r¼   \  si   € ô �l¤D×)Ò)ÙØ×Ñ˜I tÓ,€DÜ�$œ×ÒØˆä�$œ×ÒØ�z‰z‹|×!Ñ!Ó#¬<Ñ7Ð7Ü�‹:Ðr   c                óŠ   € V ^8„  d   Qh/ ^ \         9   d
   \        ;R&   ^\         9   d   \        \        \        3,          ;R&   # )r   r   r¨   )Ú__conditional_annotations__r©   r=   r   )r   s   "r   r   r      s>   € ÷ ñ ÷. (Ò 'œCÑ 'ñ/÷J	8ò 	8””Sœ#�X•ñ 	8òKr   >   Ú0ÚnoÚoffÚfalse>   Ú1ÚonÚyesÚtrue>   rb   ra   rt   r•   rn   rN   r“   rS   r,   rP   Úproviderr”   r¤   r§   r‚   r¦   r˜   rV   r¥   rX   r¢   r–   rZ   r—   Ústale_timeout_secondsÚrequest_timeout_secondsr\   rŽ   rH   )3r!  Ú__doc__Úloggingrc   Útypingr   r   r   r   r   r   Úurllib.parser   Úhermes_cli.route_identityr	   Ú	getLoggerr   r©   r   r   r0   Ú	frozensetrê   rë   r4   r:   rD   rL   r¨   rª   rl   r~   r³   r¸   r¿   rÔ   rÛ   rß   rã   rç   rí   rò   rù   r­   rÿ   r  r	  r  r  r¼   r   )r!  s   @r   Ú<module>r4     s‰  øðöó Û 	ß =× =Ý !å >ð 
×	Ò	Ð.Ó	/€ñ #&£%Ð Ó 'õð Ð ØÐ%ØÐ%ØÐ*ØÐ)ØÐ"ØÐ)ØÐ)ØÐ%ØÐ.ØÐ$ØÐ!ØÐ*ð,Ð ñ  Ò4Ó5€ÙÒ2Ó3€õ;õõ	õð$ ˆiØˆzØˆzØˆiØ�Ø�OØÐ%ØÐ(ØÐ6ð	"8€ó 	8ò3Ð õõ<ðD]Ø')÷]ð@Ø')÷õ*÷-õ`÷6õ&>õ	õ÷÷"
8õO÷
÷.÷÷ *÷Z÷8r   