Ë
    âß²j×f  ã                   óà  — U d Z ddlZddlZddlmZmZmZmZmZm	Z	 ddl
mZ ddlmZ  ej                  d«      Z e«       Zeed<   ded	ed
ededdf
d„ZddddddddddddddœZ eh d£«      Z eh d£«      Zdedefd„Zdedefd„Zdedefd„Zdedede	eeeeef      f   fd„Zdddddd d!d"d#d$œ	Zeeef   ed%<   h d&£Zd'eeef   dedefd(„Z d)ede	eeef   e!f   fd*„Z"d+d,œd'ededeeeef      fd-„Z#d+d,œd'ededeeeef      fd.„Z$d/edeeeef      fd0„Z%	 dGd1eeeef      deeeef      fd2„Z&ded3eeeeef         d1eeeef      fd4„Z'	 	 dHded3eeeeef         d1eeeef      defd5„Z(d'eeef   d6edeeeef      fd7„Z)d6eded3eeeeef         d1eeeef      deeeef      f
d8„Z*dedee!   fd9„Z+	 	 dHded3eeeeef         d1eeeef      deeef   fd:„Z,	 	 dHd;eeef   ded3eeeeef         d1eeeef      ddf
d<„Z-d=edeeef   fd>„Z.	 	 dHded3eeeeef         d1eeeef      deeef   fd?„Z/	 	 dHd;eeef   ded3eeeeef         d1eeeef      ddf
d@„Z0	 	 dHded3eeeeef         d1eeeef      defdA„Z1	 	 dHd6eded3eeeeef         d1eeeef      dee2   f
dB„Z3	 	 dHd6ededCed3eeeeef         d1eeeef      dee!   fdD„Z4dEeeeef      de!fdF„Z5y)Ia²  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.configÚ_PROVIDER_NORMALIZE_WARNEDÚprovider_keyÚ	signatureÚmsgÚargsÚreturnc                 ó|   — | xs d|f}|t         v ryt         j                  |«       t        j                  |g|¢­Ž  y)zKEmit ``logger.warning(msg, *args)`` at most once per (provider, signature).ú?N)r   ÚaddÚloggerÚwarning)r   r   r   r   Ú	dedup_keys        ú@/home/ubuntu/.hermes/hermes-agent/hermes_cli/config_providers.pyÚ_warn_once_per_providerr      s<   € àÒ$  iÐ0€IØÔ.Ñ.ØÜ×"Ñ" 9Ô-Ü
‡N�N�3Ð˜Ôó    Úchat_completionsÚcodex_responsesÚanthropic_messagesÚbedrock_converse)ÚopenaiÚopenai_chatzopenai-chatzchat-completionsÚchatcompletionsÚ	responsesÚopenai_responseszopenai-responsesÚ	anthropiczanthropic-messagesÚmessagesÚbedrockzbedrock-converse>   Ú0ÚnoÚoffÚfalse>   Ú1ÚonÚyesÚtrueÚapi_modec                 ój   — | j                  «       }t        j                  |j                  «       |«      S )zUMap alias ``api_mode`` spellings to canonical transport names (unknown pass through).)ÚstripÚ_API_MODE_ALIASESÚgetÚlower)r.   Úcleaneds     r   Ú_canonical_api_moder5   <   s'   € à�n‰nÓ€GÜ× Ñ  §¡£°'Ó:Ð:r   Úvaluec                 ó:   — | €yt        | «      j                  «       S )z%Provider identity fields are strings.Ú )Ústrr0   )r6   s    r   Úcoerce_provider_idr:   B   s   € à€}ØÜˆu‹:×ÑÓÐr   Ú	providersc                 ó„   — t        | t        «      si S i }| j                  «       D ]  \  }}t        |«      }|sŒ|||<   Œ |S )zYCopy a ``providers:`` mapping so keys are strings (unquoted YAML ``2070:`` loads as int).)Ú
isinstanceÚdictÚitemsr:   )r;   ÚoutÚstoredr6   Úkeys        r   Ústringify_provider_maprC   I   sM   € ä�i¤Ô&Øˆ	Ø€CØ"Ÿ™Ó*ò ‰ˆ�Ü  Ó(ˆÚØˆC�ŠHðð €Jr   rB   c                 ó  — t        | t        «      syt        |«      }|sy| j                  |«      }t        |t        «      r||fS | j	                  «       D ]*  \  }}t        |«      |k(  sŒt        |t        «      sŒ&||fc S  y)zXReturn ``(stored_key, entry)`` matching *key* by string identity (exact hit, then scan).©NN)r=   r>   r:   r2   r?   )r;   rB   ÚwantÚexactrA   Úentrys         r   Úfind_provider_entryrI   U   s€   € ä�i¤Ô&ØÜ˜cÓ"€DÙØØ�M‰M˜$Ó€EÜ�%œÔØ�Uˆ{ÐØ"Ÿ™Ó*ò !‰ˆ�Ü˜fÓ%¨Ó-´*¸UÄDÕ2IØ˜5�=Ò ð!ð r   Úapi_keyÚbase_urlÚkey_envÚdefault_modelÚcontext_lengthÚrate_limit_delayÚsession_affinity_header)	ÚapiKeyÚbaseUrlÚapiModeÚkeyEnvÚ	apiKeyEnvÚdefaultModelÚcontextLengthÚrateLimitDelayÚsessionAffinityHeaderÚ_CAMEL_ALIASES>   ÚapiÚurlÚnameÚmodelÚmodelsrJ   Úkey_cmdrL   r.   rK   ÚproviderÚ	transportÚ
extra_bodyÚ
ssl_verifyÚapi_key_envÚssl_ca_certÚcapabilitiesrM   Úextra_headersrN   Údiscover_modelsÚcatalog_providerrO   Úmodels_discoveredÚstale_timeout_secondsÚrequest_timeout_secondsrP   rH   c                 óP  — dD ]¡  }| j                  |«      }t        |t        «      r|j                  «       sŒ5|j                  «       }t	        j
                  d|«      r|c S t        |«      }|j                  r|j                  r|c S t        j                  d|xs d||«       Œ£ y)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.
    )rK   r\   r[   z	\{[^}]+\}uP   providers.%s: '%s' value '%s' is not a valid URL (no scheme or host) â€” skippedr   r8   )r2   r=   r9   r0   ÚreÚsearchr	   ÚschemeÚnetlocr   r   )rH   r   Úurl_keyÚraw_urlÚ	candidateÚparseds         r   Ú_pick_provider_base_urlrw   }   s–   € ð .ò 5ˆØ—)‘)˜GÓ$ˆÜ˜7¤CÔ(¨W¯]©]¬_ØØ—M‘M“Oˆ	ô
 �9‰9�\ 9Ô-ØÒÜ˜)Ó$ˆØ�=Š=˜VŸ]š]ØÒÜ�‰ð.àÒ˜C ¨)õ	5ð5ð$ r   r_   c                 ó®  — d}t        | t        «      r9| r7t        | «      }|j                  dd«      du rd}|j                  dd«       ||fS t        | t        «      rñ| rïi }| D ]ä  }t        |t        «      r$|j                  «       ri ||j                  «       <   Œ7t        |t        «      sŒH|j                  d«      }t        |t        «      r|j                  «       s|j                  d«      }t        |t        «      r|j                  «       sŒ«|j                  «       D ��ci c]  \  }}|dvsŒ||“Œ c}}||j                  «       <   Œæ ||fS i |fS c c}}w )	a
  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__Úidr]   >   r{   r]   )r=   r>   ÚpopÚlistr9   r0   r2   r?   )r_   Ú
discoveredÚmodels_copyÚnormalized_modelsÚitemÚmodel_idÚkÚvs           r   Ú_normalize_provider_modelsr…   ˜   sC  € ð €JÜ�&œ$Ô¡Fô ˜6“lˆØ�?‰?Ð9¸4Ó@ÀDÑHØˆJØ�‰Ð6¸Ô=Ø˜JÐ&Ð&Ü�&œ$Ô¡FØ,.ÐØò 	JˆDÜ˜$¤Ô$¨¯©¬Ø24Ð! $§*¡*£,Ñ/ØÜ˜d¤DÔ)ØØ—x‘x “~ˆHÜ˜h¬Ô,°H·N±NÔ4DØŸ8™8 FÓ+�Ü˜h¬Ô,°H·N±NÔ4DØà!%§¡£÷3JÙ˜˜A°¸.Ò1H��1‘ó3JÐ˜hŸn™nÓ.Ò/ð	Jð ! *Ð,Ð,Øˆzˆ>Ðùó3Js   Ä EÄ-Er8   ©r   c                ób  ‡ ‡— t        ‰ t        «      syt        ‰ «      Š t        |«      }d‰ v rd‰ vr‰ d   ‰ d<   t        j	                  «       D ].  \  }}|‰ v sŒ|‰ vsŒt        |d|› �d|xs d||«       ‰ |   ‰ |<   Œ0 t        ‰ j                  «       «      t        z
  t        t        j                  «       «      z
  }|rFt        |ddj                  t        |«      «      z   d	|xs dd
j                  t        |«      «      «       t        ‰ |«      }t        ‰ j                  d«      «      xs |}|r|sy||dœŠ|r|‰d<   dt        dt        fˆ fd„}dt        dt        ddfˆfd„} |d |d«      «        |d |d«      «        |dd«      }	 |d|	«       |	r'‰ j                  d«      r‰ j                  d«      s|	‰d<    |dd«      }
 |d|
rt        |
«      nd«        |d |dd«      «        |d |d«      «       t!        ‰ j                  d«      «      \  }} |d|«       ‰ j                  d«      du s|rd‰d<   ‰ j                  d«      }t        |t        «      rK |d|j	                  «       D ��ci c](  \  }}t        |t        «      rt        |t"        «      r||“Œ* c}}«       d d!„ fd"d#„ fd$d%„ ffD ]%  \  }} |‰ j                  |«      «      sŒ‰ |   ‰|<   Œ' t        ‰ j                  d&«      t        «      rt        ‰ d&   «      ‰d&<    |d't%        ‰ j                  d'«      «      «        |d( |d(«      «        |d) |d)«      «       ‰ j                  d*«      }t        |t"        «      r|‰d*<   ‰S t        |t        «      r#|j'                  «       r|j'                  «       ‰d*<   ‰S c c}}w )+z>Return a runtime-compatible custom provider entry or ``None``.Nre   rL   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, r]   )r]   rK   r   Úkeysr   c                  ó„   •— d }| D ]  }‰j                  |«      }|sŒ n t        |t        «      r|j                  «       S dS ©Nr8   )r2   r=   r9   r0   )r‰   Úvalrƒ   rH   s      €r   Ú	_strippedz3_normalize_custom_provider_entry.<locals>._strippedÞ   sF   ø€ ØˆØò 	ˆAØ—)‘)˜A“,ˆCÚÙð	ô )¨¬cÔ2ˆs�y‰y‹{Ð:¸Ð:r   Úfieldr6   c                 ó   •— |r|‰| <   y y ©N© )rŽ   r6   Ú
normalizeds     €r   Ú_putz._normalize_custom_provider_entry.<locals>._putæ   s   ø€ ÙØ %ˆJ�uÒð r   rJ   r`   r.   rb   r8   r^   rM   rj   r_   rk   Trg   rN   c                 ó0   — t        | t        «      xr | dkD  S ©Nr   )r=   Úint©r„   s    r   ú<lambda>z2_normalize_custom_provider_entry.<locals>.<lambda>  s   € ¤Z°´3Ó%7Ò%A¸AÀ¹E€ r   rO   c                 ó<   — t        | t        t        f«      xr | dk\  S r•   )r=   r–   Úfloatr—   s    r   r˜   z2_normalize_custom_provider_entry.<locals>.<lambda>  s   € ¤z°!´c¼5°\Ó'BÒ'MÀqÈAÁv€ r   ri   c                 ó.   — t        | t        t        f«      S r�   )r=   Úboolr9   r—   s    r   r˜   z2_normalize_custom_provider_entry.<locals>.<lambda>  s   € ¤j°´T¼3°KÓ&@€ r   rc   rh   rP   rf   rd   )r=   r>   r:   rZ   r?   r   Úsetr‰   Ú_KNOWN_PROVIDER_KEYSÚjoinÚsortedrw   r2   r9   r   r5   r…   rœ   Únormalize_extra_headersr0   )rH   r   ÚcamelÚsnakeÚunknownrK   r]   r�   r“   rL   r.   Úmodels_dictr~   rg   rB   r6   rŽ   Úokrd   r’   s   `                  @r   Ú _normalize_custom_provider_entryr§   º   sÐ  ù€ ô �eœTÔ"Øô �‹K€EÜ% lÓ3€Là˜Ñ )°5Ñ"8Ø  Ñ/ˆˆiÑÜ&×,Ñ,Ó.ò (‰ˆˆuØ�EŠ>˜e¨5Ò0Ü#Ø  u gÐ.ð9àÒ#  U¨Eô	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ˆ
�>Ñ"ð;œð ;¤õ ;ð&”Cð &¤ð &¨õ &ñ 	ˆ‘I˜iÓ(Ô)Ùˆ‘I˜iÓ(Ô)Ù˜	 =Ó1€GÙˆ�GÔÙ�5—9‘9˜]Ô+°E·I±I¸iÔ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Ô#¬
°5¼$Ô(?ð �‰JóAô 	Bð
 
ÑAÐBØ	ÑMÐNØ	Ñ@ÐAðò -‰	ˆˆrñ
 ˆe�i‰i˜ÓÕØ % e¡ˆJ�uÒð-ô �%—)‘)˜LÓ)¬4Ô0Ü#'¨¨lÑ(;Ó#<ˆ
�<Ñ ñ 	ˆÔ1°%·)±)¸OÓ2LÓMÔNÙÐ	"¡IÐ.GÓ$HÔIÙˆ™	 -Ó0Ô1à—‘˜<Ó(€JÜ�*œdÔ#Ø#-ˆ
�<Ñ ð Ðô 
�J¤Ô	$¨×)9Ñ)9Ô);Ø#-×#3Ñ#3Ó#5ˆ
�<Ñ àÐùó3As   É4-N+c                óŒ   — t        | |¬«      }|€yd|d   i}dD ]  }||v sŒ||   ||<   Œ d|v r|d   |d<   d|v r|d   |d	<   |S )
zDTranslate a legacy custom provider entry to the v12 providers shape.r†   Nr[   rK   )r]   rJ   rL   r`   r_   rk   rN   rO   ri   rc   rh   rP   rf   rd   rj   r^   rM   r.   rb   )r§   )rH   r   r’   Úprovider_entryrŽ   s        r   Ú)_custom_provider_entry_to_provider_configrª     s‰   € ô 2°%ÀlÔS€JØÐØà&+¨Z¸
Ñ-CÐ%D€NðTò 6ˆð �JÒØ$.¨uÑ$5ˆN˜5Ò!ð6ð �*ÑØ*4°WÑ*=ˆ�Ñ'Ø�ZÑØ&0°Ñ&<ˆ�{Ñ#ØÐr   Úproviders_dictc                 óê   — t        | t        «      sg S g }| j                  «       D ]K  \  }}t        |t        «      rt        |«      sŒ"t	        |t        |«      ¬«      }|€Œ;|j                  |«       ŒM |S )zUNormalize enabled ``providers`` config entries into the legacy custom-provider shape.r†   )r=   r>   r?   Úis_provider_enabledr§   r:   Úappend)r«   Úcustom_providersrB   rH   r’   s        r   Ú"providers_dict_to_custom_providersr°   /  sw   € ä�n¤dÔ+Øˆ	Ø-/ÐØ$×*Ñ*Ó,ò 0‰
ˆˆUÜ�eœTÔ"Ô+>¸uÔ+EØÜ5°eÔJ\Ð]`ÓJaÔbˆ
ØÑ!Ø×#Ñ# JÕ/ð0ð Ðr   Úconfigc                 ó(  — ddl m} | € |«       } | j                  d«      }|�;t        |t        «      s+t
        j                  dt        |«      j                  «       g }|xs g D �cg c]  }t        |«      ‘Œ }}|t        | j                  d«      «      z  }dt        t        t        f   dt        dt        fd	„}g }t        «       }t        «       }|D ]¸  }	|	€Œ ||	d
«      }
 ||	d«      }t        |	j                  dd«      xs d«      j                  «       j!                  d«      j#                  «       }|| ||	d«      f}|
r|
|v rŒu|r|r||v rŒ~|j%                  |	«       |
r|j'                  |
«       |sŒ¥|sŒ¨|j'                  |«       Œº |S c c}w )z§Deduplicated list view over legacy ``custom_providers`` and v12+ ``providers``.

    Never materialised back into config.yaml (it would duplicate entries in UIs).
    r   )Ú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;   rH   rŽ   r   c                 óx   — t        | j                  |d«      xs d«      j                  «       j                  «       S r‹   )r9   r2   r0   r3   )rH   rŽ   s     r   Ú_normz.get_compatible_custom_providers.<locals>._normT  s/   € Ü�5—9‘9˜U BÓ'Ò-¨2Ó.×4Ñ4Ó6×<Ñ<Ó>Ð>r   r   r]   rK   r8   ú/r^   )Úhermes_cli.configr³   r2   r=   r}   r   r   ÚtypeÚ__name__r§   r°   r   r9   r   r�   r0   Úrstripr3   r®   r   )r±   r³   r¯   ÚeÚ
candidatesrµ   Ú
compatibleÚseen_provider_keysÚseen_name_url_pairsrH   r   r]   rK   Úpairs                 r   Úget_compatible_custom_providersrÁ   =  s¦  € õ .Ø€~Ù“ˆà—z‘zÐ"4Ó5ÐØÐ#¬JÐ7GÌÔ,Nô 	�‰ðfäÐ!Ó"×+Ñ+ô	-ð ÐØ@PÒ@VÐTVÖX¸!Ô2°1Õ5ÐX€JÐXØÔ4°V·Z±ZÀÓ5LÓMÑM€Jð?”Tœ#œs˜(‘^ð ?¬Cð ?´Có ?ð (*€JÜ!›eÐÜ"›uÐØò *ˆØˆ=ØÙ˜U NÓ3ˆÙ�U˜FÓ#ˆÜ�u—y‘y ¨RÓ0Ò6°BÓ7×=Ñ=Ó?×FÑFÀsÓK×QÑQÓSˆØ�h¡ e¨WÓ 5Ð6ˆÙ˜LÐ,>Ñ>ØÙ‘H Ð)<Ñ!<ØØ×Ñ˜%Ô ÙØ×"Ñ" <Ô0Ú’HØ×#Ñ# DÕ)ð*ð  Ðùò3 Ys   Á&Fr¯   c              #   ó  K  — ddl m} |€		  ||«      }| rt        |t        «      syt        | «      }|sy|D ]:  }t        |t        «      sŒt        |j                  d«      «      }|sŒ1||k(  sŒ7|–— Œ< y# t        $ r g }Y Œnw xY w­w)u¦   Yield entries whose normalized route identity equals *base_url*.

    None *custom_providers* â†’ ``get_compatible_custom_providers(config)`` (failure â†’ none).
    r   )rÁ   NrK   )r·   rÁ   Ú	Exceptionr=   r}   r
   r>   r2   )rK   r¯   r±   rÁ   Ú
target_urlrH   Ú	entry_urls          r   Ú_entries_for_routerÆ   m  s˜   è ø€ õ BØÐð	"Ù>¸vÓFÐñ œ:Ð&6¼Ô=ØÜ)¨(Ó3€JÙØØ!ò ˆÜ˜%¤Ô&ØÜ,¨U¯Y©Y°zÓ-BÓCˆ	Ú˜ jÓ0Ø‹Kñøô ò 	"Ø!Òð	"üs4   ‚	BŒA5 ”ABÁ(BÁ.BÁ5BÂ BÂBÂBc                 ó¸   — t        | ||«      D ]J  }dD ]C  }|j                  |«      }t        |t        «      sŒ%|j	                  «       sŒ6t        |«      c c S  ŒL y)aN  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).
    )r.   rb   r8   )rÆ   r2   r=   r9   r0   r5   )rK   r¯   r±   rH   rŽ   r6   s         r   Úget_custom_provider_api_moderÈ   ˆ  s\   € ô $ HÐ.>ÀÓGò 2ˆØ.ò 	2ˆEØ—I‘I˜eÓ$ˆEÜ˜%¤Õ%¨%¯+©+­-Ü*¨5Ó1Ô1ñ	2ð2ð
 r   r^   c                 ó�   — | j                  d«      }t        |t        «      sy|j                  |«      }t        |t        «      r|S dS )zAReturn ``entry.models[model]`` when both are mappings, else None.r_   N)r2   r=   r>   )rH   r^   r_   Ú	model_cfgs       r   Ú_route_model_cfgrË   ›  s?   € à�Y‰Y�xÓ €FÜ�fœdÔ#ØØ—
‘
˜5Ó!€IÜ" 9¬dÔ3ˆ9Ð=¸Ð=r   c              #   óV   K  — t        |||«      D ]  }t        || «      }|€Œ|–— Œ y­w)zHYield the ``models.<model>`` mapping of every entry matching *base_url*.N)rÆ   rË   )r^   rK   r¯   r±   rH   rÊ   s         r   Ú_route_model_cfgsrÍ   ¤  s8   è ø€ ô $ HÐ.>ÀÓGò ˆÜ$ U¨EÓ2ˆ	ØÑ Ø‹Oñùs   ‚)¢)c                 ó¶   — | €y t        | t        «      r| S t        | t        «      r4| j                  «       j	                  «       }|t
        v rdS |t        v rdS d S y )NFT)r=   rœ   r9   r0   r3   Ú_FALSE_WORDSÚ_TRUE_WORDS)r6   Úlowereds     r   Ú_coerce_ssl_verifyrÒ   °  sY   € Ø€}ØÜ�%œÔØˆÜ�%œÔØ—+‘+“-×%Ñ%Ó'ˆØ¤<Ñ/ˆuÐ]¸WÌÑ=S°TÐ]ÐY]Ð]Ør   c                 óþ   — t        | ||«      D ]l  }i }|j                  d«      }t        |t        «      r#|j	                  «       r|j	                  «       |d<   t        |j                  d«      «      }|�||d<   |c S  i S )zOReturn TLS settings from a matching ``custom_providers`` / ``providers`` entry.rf   rd   )rÆ   r2   r=   r9   r0   rÒ   )rK   r¯   r±   rH   r@   ÚcaÚverifys          r   Ú get_custom_provider_tls_settingsrÖ   »  s�   € ô
 $ HÐ.>ÀÓGò ˆØ ˆØ�Y‰Y�}Ó%ˆÜ�bœ#Ô 2§8¡8¤:Ø!#§¡£ˆC�ÑÜ# E§I¡I¨lÓ$;Ó<ˆØÐØ &ˆC�ÑØŠ
ðð €Ir   Úclient_kwargsc                 ój   — t        |||«      }|j                  d«      r|d   | d<   d|v r	|d   | d<   yy)zCAttach per-provider TLS knobs to OpenAI client kwargs when matched.rf   rd   N)rÖ   r2   )r×   rK   r¯   r±   Útlss        r   Ú*apply_custom_provider_tls_to_client_kwargsrÚ   Ì  sJ   € ô +¨8Ð5EÀvÓ
N€CØ
‡w�wˆ}ÔØ'*¨=Ñ'9ˆ�mÑ$Ø�sÑØ&)¨,Ñ&7ˆ�lÒ#ð r   rh   c                 ó¨   — t        | t        «      r| si S | j                  «       D ��ci c]  \  }}|€Œ	t        |«      t        |«      “Œ c}}S c c}}w )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?   r9   )rh   rƒ   r„   s      r   r¡   r¡   Ù  sF   € ô �m¤TÔ*±-Øˆ	Ø'4×':Ñ':Ó'<×N™t˜q !ÀÁŒC�‹F”C˜“F‰NÓNÐNùÓNs
   ¨
A³Ac                 ój   — t        | ||«      D ]"  }t        |j                  d«      «      }|sŒ |c S  i S )u›   ``extra_headers`` of the first route-matching entry declaring any, else ``{}``.
    SECURITY: values may carry credentials â€” callers must never log them.rh   )rÆ   r¡   r2   )rK   r¯   r±   rH   Úheaderss        r   Ú!get_custom_provider_extra_headersrÞ   ä  s?   € ô $ HÐ.>ÀÓGò ˆÜ)¨%¯)©)°OÓ*DÓEˆÚØŠNðð €Ir   c                 óŒ   — t        |||«      }|syt        | j                  d«      xs i «      }|j                  |«       || d<   y)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>   r2   Úupdate)r×   rK   r¯   r±   rh   Úmergeds         r   Ú4apply_custom_provider_extra_headers_to_client_kwargsrã   ñ  sL   € ô 6°hÐ@PÐRXÓY€MÙØÜ�-×#Ñ#Ð$5Ó6Ò<¸"Ó=€FØ
‡M�M�-Ô Ø'-€MÐ#Ò$r   c                 ó°   — t        | ||«      D ]F  }|j                  d«      }t        |t        «      sŒ%|j	                  «       sŒ6|j	                  «       c S  y)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).
    rP   r8   )rÆ   r2   r=   r9   r0   )rK   r¯   r±   rH   Úheaders        r   Ú+get_custom_provider_session_affinity_headerræ      sO   € ô $ HÐ.>ÀÓGò "ˆØ—‘Ð4Ó5ˆÜ�fœcÕ" v§|¡|¥~Ø—<‘<“>Ò!ð"ð r   c                 ó¢  — ddl m}m} | r|sy|€	  ||€ |«       n|«      }dt        dt        t           fd„}t        | |||«      D ]  } ||j	                  d«      «      }	|	€Œ|	c S  t        |||«      D ]  }
 ||
j	                  d«      «      }	|	€Œ|	c S  y# t        $ r, |€Y y|j	                  d«      }t        |t        «      r|ng }Y Œ«w xY w)	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   ©rÁ   Úload_config_readonlyNr¯   Úrawr   c                 óV   — 	 t        | «      }|dkD  r|S d S # t        t        f$ r Y y w xY wr•   )r–   Ú	TypeErrorÚ
ValueError)rê   Úctxs     r   Ú_positive_intz9get_custom_provider_context_length.<locals>._positive_int(  s<   € ð	Ü�c“(ˆCð ˜A’gˆsÐ' 4Ð'øô œ:Ð&ò 	Ùð	ús   ‚ –(§(rN   )r·   rÁ   ré   rÃ   r2   r=   r}   r   r   r–   rÍ   rÆ   )r^   rK   r¯   r±   rÁ   ré   rê   rï   rÊ   rî   rH   s              r   Ú"get_custom_provider_context_lengthrð     s  € ÷ XÙ™ØØÐð	Dñ  ?ÐY_ÐYgÑ?SÔ?UÐmsÓtÐð(œ3ð (¤8¬C¡=ó (ô ' u¨hÐ8HÈ&ÓQò ˆ	Ù˜IŸM™MÐ*:Ó;Ó<ˆØ‰?ØŠJðô $ HÐ.>ÀÓGò ˆÙ˜EŸI™IÐ&6Ó7Ó8ˆØ‰?ØŠJðð øô1 ò 	DØˆ~ÙØ—*‘*Ð/Ó0ˆCÜ&0°´dÔ&;™sÀÒð		Dús   ‘B ÂCÂ&%CÃCÚ
capabilityc                 óØ   — ddl m}m} | r|r|sy|€	 |€ |«       } ||«      }t	        | |||«      D ]'  }|j                  |«      }t        |t        «      sŒ%|c S  y# t        $ r Y yw xY w)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   rè   N)r·   rÁ   ré   rÃ   rÍ   r2   r=   rœ   )	r^   rK   rñ   r¯   r±   rÁ   ré   rÊ   r6   s	            r   Ú$get_custom_provider_model_capabilityró   =  sŠ   € ÷ XÙ™©
ØØÐð	Øˆ~ñ .Ó/�Ù>¸vÓFÐô ' u¨hÐ8HÈ&ÓQò ˆ	Ø—‘˜jÓ)ˆÜ�eœTÕ"ØŠLðð øô ò 	Ùð	ús   “A Á	A)Á(A)Úprovider_cfgc                 óê   — t        | t        «      sy| j                  dd«      }t        |t        «      r|S t        |t        «      r$|j                  «       j                  «       t        vS t        |«      S )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>   r2   rœ   r9   r0   r3   rÏ   )rô   Úflags     r   r­   r­   Y  s`   € ô �l¤DÔ)ØØ×Ñ˜I tÓ,€DÜ�$œÔØˆä�$œÔØ�z‰z‹|×!Ñ!Ó#¬<Ð7Ð7Ü�‹:Ðr   r�   rE   )6Ú__doc__Úloggingro   Útypingr   r   r   r   r   r   Úurllib.parser	   Úhermes_cli.route_identityr
   Ú	getLoggerr   r�   r   Ú__annotations__r9   r   r1   Ú	frozensetrÏ   rÐ   r5   r:   r>   rC   rI   rZ   rž   rw   rœ   r…   r§   rª   r°   rÁ   rÆ   rÈ   rË   rÍ   rÒ   rÖ   rÚ   r¡   rÞ   rã   ræ   r–   rð   ró   r­   r‘   r   r   ú<module>r      sW  ðòó Û 	ß =× =Ý !å >ð 
ˆ×	Ñ	Ð.Ó	/€ñ #&£%Ð ˜CÓ 'ð¨#ð ¸#ð ÀCð ÐPSð ÐX\ó ð !Ø%Ø%Ø*Ø)Ø"Ø)Ø)Ø%Ø.Ø$Ø!Ø*ñ,Ð ñ  Ò4Ó5€ÙÒ2Ó3€ð; #ð ;¨#ó ;ð˜cð  có ð	 cð 	¨dó 	ð 3ð ¨Sð °U¸3ÀÈÈcÐSVÈhÉÑ@XÐ;XÑ5Yó ð$ ØØØØØ#Ø%Ø(Ø6ñ	"8€��S˜#�X‘ó 	8ò3Ð ð 4¨¨S¨¡>ð Àð Èó ð6 sð ¨u°T¸#¸s¸(±^ÀTÐ5IÑ/Jó ðF (*ò]Øð]Ø!$ð]Ø.6°t¸CÀ¸H±~Ñ.Fó]ðB (*òØðØ!$ðØ.6°t¸CÀ¸H±~Ñ.Fóð*°sð ¸tÀDÈÈcÈÁNÑ?Só ð (,ñ-Ø�T˜#˜s˜(‘^Ñ$ð-Ø04°T¸#¸s¸(±^Ñ0Dó-ð`Øðà˜t D¨¨c¨¡NÑ3Ñ4ðð �T˜#˜s˜(‘^Ñ$óð: 8<Ø'+ñØðà˜t D¨¨c¨¡NÑ3Ñ4ðð �T˜#˜s˜(‘^Ñ$ðð 	ó	ð&>˜D  c ™Nð >°3ð >¸8ÀDÈÈcÈÁNÑ;Só >ð	Øð	àð	ð ˜t D¨¨c¨¡NÑ3Ñ4ð	ð �T˜#˜s˜(‘^Ñ$ð		ð *2°$°s¸C°x±.Ñ)Aó		ð˜cð  h¨t¡nó ð 8<Ø'+ñØðà˜t D¨¨c¨¡NÑ3Ñ4ðð �T˜#˜s˜(‘^Ñ$ðð 15°S¸#°X±óð( 8<Ø'+ñ	
8Ø˜˜S˜‘>ð
8àð
8ð ˜t D¨¨c¨¡NÑ3Ñ4ð
8ð �T˜#˜s˜(‘^Ñ$ð	
8ð 15ó	
8ðO¨3ð O°4¸¸S¸±>ó Oð 8<Ø'+ñ
Øð
à˜t D¨¨c¨¡NÑ3Ñ4ð
ð �T˜#˜s˜(‘^Ñ$ð
ð 15°S¸#°X±ó
ð  8<Ø'+ñ	.Ø˜˜S˜‘>ð.àð.ð ˜t D¨¨c¨¡NÑ3Ñ4ð.ð �T˜#˜s˜(‘^Ñ$ð	.ð 15ó	.ð" 8<Ø'+ñØðà˜t D¨¨c¨¡NÑ3Ñ4ðð �T˜#˜s˜(‘^Ñ$ðð 14óð& 8<Ø'+ñ	*Øð*àð*ð ˜t D¨¨c¨¡NÑ3Ñ4ð*ð �T˜#˜s˜(‘^Ñ$ð	*ð 19¸±ó	*ðb 8<Ø'+ñØðàðð ðð ˜t D¨¨c¨¡NÑ3Ñ4ð	ð
 �T˜#˜s˜(‘^Ñ$ðð
 19¸±óð8 h¨t°C¸°H©~Ñ&>ð À4ô r   