Ë
    âß²jß+  ã                   ó¸  — U d Z ddlZddlmZ ddlmZmZ ddlmZ ddl	m
Z
 ddlmZ  ej                  e«      Zdaee   dz  ed<   d	Zd
edz  defd„Zdedz  dedz  fd„ZddddœZdZeD � ��ci c]"  } ej5                  «       D ]  \  }}| |z   | |f“Œ Œ$ c}}} Zeeeeeedf   f   f   ed<    G d„ de«      Z eddddddddd ¬!«	      Z e
e«       yc c}}} w )"zOpenRouter provider profile.é    N)ÚAny)Úget_affinity_scopeÚget_conversation_context)Ú_cache_scope_from_session_id)Úregister_provider)ÚProviderProfileÚ_CACHE)zclaude-3zclaude-opus-4-0zclaude-opus-4.0zclaude-opus-4-1zclaude-opus-4.1zclaude-sonnet-4-0zclaude-sonnet-4.0zclaude-opus-4-2025zclaude-sonnet-4-2025zclaude-opus-4-5zclaude-opus-4.5zclaude-sonnet-4-5zclaude-sonnet-4.5zclaude-haiku-4-5zclaude-haiku-4.5ÚmodelÚreturnc                 óŠ   ‡— | xs dj                  «       Š‰j                  d«      sd‰vryt        ˆfd„t        D «       «       S )zRTrue for Anthropic models that reject any disable-thinking form (unknown -> True).Ú )z
anthropic/Úclauder   Fc              3   ó&   •K  — | ]  }|‰v –— Œ
 y ­w)N© )Ú.0ÚsubÚms     €úP/home/ubuntu/.hermes/hermes-agent/plugins/model-providers/openrouter/__init__.pyú	<genexpr>z4_anthropic_reasoning_is_mandatory.<locals>.<genexpr>#   s   øè ø€ ÒP �3˜!”8ÑPùs   ƒ)ÚlowerÚ
startswithÚanyÚ(_ANTHROPIC_REASONING_OPTIONAL_SUBSTRINGS)r
   r   s    @r   Ú!_anthropic_reasoning_is_mandatoryr      sA   ø€ à	Š�"×ÑÓ€AØ�<‰<Ð0Ô1°hÀaÑ6GØÜÓPÔ'OÔPÓPÐPÐPó    Ú
session_idc                 óH   — t        t        «       xs t        «       xs | «      S )uæ   Declared routing scope, then ambient conversation, then explicit session_id.
    Aux call sites (compression, titles, vision, MoAâ€¦) pass no ``session_id``,
    so the ambient lineage ROOT keeps them pinned to their conversation.)r   r   r   ©r   s    r   Ú_sticky_keyr   &   s"   € ô (Ô(:Ó(<Ò(hÔ@XÓ@ZÒ(hÐ^hÓiÐir   )ÚopenaiÚazurezazure/us)zopenai/fast)zopenai/flex)r   z-fastz-flex)zopenai/gpt-6-astrazopenai/gpt-6-astra-pro.ÚOPENROUTER_ENDPOINT_PINSc                   ó  ‡ — e Zd ZdZedeeef   dedz  deeef   dz  fd„«       Zddddœd	edz  d
edz  de	de
e   dz  fˆ fd„Zddœdedz  dedeeef   fd„Zdddddœdedz  dededz  dedz  dedeeeef   eeef   f   fd„Zˆ xZS )ÚOpenRouterProfileuM   OpenRouter aggregator â€” provider preferences, reasoning config passthrough.Úcfgr
   Nr   c           	      óª  — | j                  d«      }| j                  d«      du xs |dk(  }|s|s| S 	 ddlm} ddlm}  ||«      }|r|j                  d«      s| S |r|j                  d	«      rd
S | S  |||j                  d«      «      }|r5||k7  r0t        j                  d||||j                  d«      «       i | ¥d|i¥} | S # t
        $ r | cY S w xY w)a³  Clamp ``cfg["effort"]`` to the model's catalog-advertised levels.

        Returns None when the config is a disable and the catalog marks the
        route reasoning-mandatory (the caller omits the field).

        OpenRouter's /v1/models entries publish ``reasoning.supported_efforts``
        per model (ported from PrimeIntellect-ai/prime-agent#1258). Sending an
        unsupported effort (e.g. ``ultra`` to a route that stops at ``high``)
        yields provider 4xx errors; clamp to the nearest LOWER supported level
        instead. No-op when the catalog is unreachable, the model is unlisted,
        or no supported_efforts list is published (None = all levels accepted).
        ÚeffortÚenabledFÚnoner   )Ú#clamp_reasoning_effort_to_supported)Ú'openrouter_model_reasoning_capabilitiesÚsupports_reasoningÚ	mandatoryNÚsupported_effortsuT   openrouter: clamped reasoning effort %r â†’ %r for %s (catalog supported_efforts=%s))ÚgetÚhermes_cli.modelsr*   Ú hermes_cli.models_reasoning_capsr+   Ú	ExceptionÚloggerÚdebug)r%   r
   r'   Údisabledr*   r+   ÚcapsÚclampeds           r   Ú_clamp_reasoning_to_catalogz-OpenRouterProfile._clamp_reasoning_to_catalog=   sò   € ð —‘˜Ó"ˆØ—7‘7˜9Ó%¨Ð.ÒB°&¸FÑ2BˆÙ™hØˆJð	ÝMÝ`á:¸5ÓAˆDÙ˜tŸx™xÐ(<Ô=Ø�
ñ Ø#Ÿx™x¨Ô4�tÐ=¸#Ð=Ù9Ø˜Ÿ™Ð!4Ó5óˆGñ
 �w &Ò(Ü�L‰LØfØ˜ ¨¯©Ð1DÓ(Eôð -�SÐ,˜( GÑ,ˆCØˆ
øô ò 	ØŠJð	ús#   ³(C ÁC Á1C Á3C ÃCÃCg       @©Úapi_keyÚbase_urlÚtimeoutr:   r;   r<   c                ó¦   •— t         �t         S 	 t        ‰| �	  d||¬«      }|�|a |S # t        $ r }t        j                  d|«       Y d}~yd}~ww xY w)z•Public OpenRouter catalog (no auth), cached per process. Tool-call
        filtering happens in hermes_cli/models.py, which the picker reaches first.Nr9   zfetch_models(openrouter): %s)r	   ÚsuperÚfetch_modelsr2   r3   r4   )Úselfr:   r;   r<   ÚresultÚexcÚ	__class__s         €r   r?   zOpenRouterProfile.fetch_modelsh   sb   ø€ ô ÐÜˆMð	Ü‘WÑ)°$ÀÐSZÐ)Ó[ˆFð ÐØˆFØˆøô ò 	Ü�L‰LÐ7¸Ô=Üûð	ús   �' §	A°AÁAr   r   Úcontextc                ó  — i }t        |«      }|r||d<   |j                  d«      }t        j                  |j                  d«      xs d«      }|rD|d   |j                  d«      k(  r|xs i j                  d«      si |xs i ¥dt        |d   «      i¥}|r||d<   |j                  d	«      }|j                  d«      xs dd
k(  r-|�+|dk7  r&	 t	        |«      }|�d|cxk  rdk  rn |S d|dœg|d<   |S # t
        t        f$ r d }Y Œ/w xY w)Nr   Úprovider_preferencesr
   r   r   Úonlyé   ÚproviderÚopenrouter_min_coding_scorezopenrouter/pareto-codeg        g      ð?zpareto-router)ÚidÚmin_coding_scoreÚplugins)r   r/   r"   ÚlistÚfloatÚ	TypeErrorÚ
ValueError)	r@   r   rD   ÚbodyÚ
sticky_keyÚprefsÚpinÚscoreÚscore_fs	            r   Úbuild_extra_bodyz"OpenRouterProfile.build_extra_bodyy   s/  € Ø!ˆô ! Ó,ˆ
ÙØ!+ˆD�ÑØ—‘Ð2Ó3ˆÜ&×*Ñ*¨7¯;©;°wÓ+?Ò+EÀ2ÓFˆñ ˜˜A™ '§+¡+¨gÓ"6Ò6¸EºKÀR×;LÑ;LÈVÔ;TØ;˜š Ð; f¬d°3°q±6«lÑ;ˆEÙØ$ˆD�Ñà—‘Ð9Ó:ˆØ�K‰K˜Ó Ò& BÐ+CÒCÈÐHYÐ^cÐgiÒ^iðÜ ›,�ð Ð" s¨gÔ'<¸Ô'<àˆð +:ÈwÑ#WÐ"X��Y‘Øˆøô	 œzÐ*ò Ø’ðús   ÃC3 Ã3DÄDF)Úreasoning_configr,   r
   r   rY   r,   c                óš  — i }i }t         j                  |xs d«      }|r|d   |k7  r|d   |d<   |rpt        |«      r8|xs i }	|	j                  d«      }
|	j                  dd«      dur:|
r8|
dk7  r3|
|d	<   n-|�#| j                  t	        |«      |«      }|�||d
<   ndddœ|d
<   t        |«      }|r|r|j                  d«      rd|i|d<   ||fS )z”Pass reasoning_config as extra_body.reasoning; pin Grok's cache via x-grok-conv-id;
        rewrite speed-tier slugs to their OpenRouter base model.r   r   r
   r'   r(   TFr)   Ú	verbosityÚ	reasoningÚmedium)r(   r'   )z
x-ai/grok-z	xai/grok-zx-grok-conv-idÚextra_headers)r"   r/   r   r8   Údictr   r   )r@   rY   r,   r
   r   rD   Ú
extra_bodyÚ	top_levelrU   r%   r'   r7   Úgrok_conv_ids                r   Úbuild_api_kwargs_extrasz)OpenRouterProfile.build_api_kwargs_extras“   s  € ð &(ˆ
Ø$&ˆ	Ü&×*Ñ*¨5ª;°BÓ7ˆÙ�3�q‘6˜U’?Ø!$ Q¡ˆI�gÑÙô( 1°Ô7Ø&Ò,¨"�ØŸ™ Ó*�Ø—7‘7˜9 dÓ+°5Ñ8¹VÈÐRXÒHXØ-3�I˜kÒ*Ø!Ð-Ø×:Ñ:ÜÐ)Ó*¨Eó�ð Ð&Ø.5�J˜{Ò+à6:ÀhÑ*O�
˜;Ñ'ä" :Ó.ˆÙ™E e×&6Ñ&6Ð7RÔ&SØ*:¸LÐ)IˆI�oÑ&Ø˜9Ð$Ð$r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ústaticmethodr_   Ústrr   r8   rO   rN   r?   rX   ÚboolÚtuplerc   Ú__classcell__)rC   s   @r   r$   r$   :   s&  ø„ ÙWàð(¨¨c°3¨h©ð (ÀÀdÁ
ð (ÈtÐTWÐY\ÐT\É~Ð`dÑOdò (ó ð(ðV (,ÀDÐ[^òØ ™*ðØ7:¸T±zðØSXðà	ˆc‰�TÑ	õð" <@ò ¨c°D©jð ÈCð ÐTXÐY\Ð^aÐYaÑTbó ð6 26ÐRWØ ¸4ò0%Ø#'¨$¡;ð0%ØKOð0%à�T‰zð0%à.1°D©jð0%àLOð0%ð 
ˆt�C˜�H‰~˜t C¨ H™~Ð-Ñ	.÷0%r   r$   Ú
openrouter)Úor)ÚOPENROUTER_API_KEYÚ
OpenRouteru*   OpenRouter â€” unified API for 200+ modelszhttps://openrouter.ai/keyszhttps://openrouter.ai/api/v1z#https://openrouter.ai/api/v1/models)zanthropic/claude-sonnet-4.6zopenai/gpt-5.4zdeepseek/deepseek-chatzgoogle/gemini-3.8-flashzgoogle/gemini-3.7-flashzqwen/qwen3-plus)	ÚnameÚaliasesÚenv_varsÚdisplay_nameÚdescriptionÚ
signup_urlr;   Ú
models_urlÚfallback_models) rg   ÚloggingÚtypingr   Úagent.portal_tagsr   r   Úagent.transports.codexr   Ú	providersr   Úproviders.baser   Ú	getLoggerrd   r3   r	   rN   ri   Ú__annotations__r   rj   r   r   Ú_SPEED_TIER_ENDPOINTSÚ_SPEED_TIERED_BASESÚitemsr"   r_   rk   r$   rm   )ÚbaseÚsuffixÚtagss   000r   ú<module>r‡      sN  ðÚ "ã Ý ç JÝ ?Ý 'Ý *à	ˆ×	Ñ	˜8Ó	$€à€ˆˆS‰	�DÑÓ ð,Ð (ðQ¨S°4©Zð Q¸Dó Qðj˜C $™Jð j¨3°©:ó jð =ÐGWÐbrÑsÐ ØFÐ à,?÷Dð DØ$(ÐTi×ToÑToÓTqòDÙDPÀFÈD€Dˆ6�M�D˜$�<ÑðDØôDÐ ˜$˜s E¨#¨u°S¸#°X©Ð*>Ñ$?Ð?Ñ@ó ô
I%˜ô I%ñX Ø	˜wÐ1HÐWcØ<ÐIeØ+Ð8]ðô	€
ñ �*Õ ùôwDs   Á0'C