§
    øžyj8+  ã                  ó    — d Z ddlmZ ddlZddlmZmZ ddlmZ  ej	        e
¦  «        Z e¦   «         Zdd„Ze G d	„ d
¦  «        ¦   «         ZdS )u‘  Provider profile base class.

A ProviderProfile declares everything about an inference provider in one place:
auth, endpoints, client quirks, request-time quirks. The transport reads this
instead of receiving 20+ boolean flags.

Provider profiles are DECLARATIVE â€” they describe the provider's behavior.
They do NOT own client construction, credential rotation, or streaming.
Those stay on AIAgent.
é    )ÚannotationsN)Ú	dataclassÚfield)ÚAnyÚreturnÚstrc                 ó<   — 	 ddl m}  d| › �S # t          $ r Y dS w xY w)u  Return a ``hermes-cli/<version>`` UA string, with a stable fallback.

    Used by ``ProviderProfile.fetch_models`` so the catalog probe is not
    served the default ``Python-urllib/<ver>`` UA â€” some providers
    (OpenCode Zen, etc.) sit behind a WAF that returns 403 for that.
    r   )Ú__version__zhermes-cli/z
hermes-cli)Ú
hermes_clir
   Ú	Exception)Ú_vers    ú4/home/ragecks/.hermes/hermes-agent/providers/base.pyÚ_profile_user_agentr      sI   € ðØ2Ð2Ð2Ð2Ð2Ð2Ø#˜TÐ#Ð#Ð#øÝð ð ð Øˆ|ˆ|ðøøøs   ‚
 �
šc                  ó˜  — e Zd ZU dZded<   dZded<   dZded<   d	Zded
<   d	Zded<   d	Z	ded<   dZ
ded<   d	Zded<   d	Zded<   dZded<   dZded<   dZded<   dZded<   dZded<   dZded<   d	Zded<    ee¬¦  «        Zded<   dZded <   dZd!ed"<   d	Zded#<   dd$œd@d'„ZdAd(„ZdBd+„Zdd,œdCd1„Zdd2œdDd6„ZdEd7„ZdFd9„Z ddd:d;œdGd?„Z!dS )HÚProviderProfileuA   Base provider profile â€” subclass or instantiate with overrides.r   ÚnameÚchat_completionsÚapi_mode© ÚtupleÚaliasesÚ Údisplay_nameÚdescriptionÚ
signup_urlÚenv_varsÚbase_urlÚ
models_urlÚapi_keyÚ	auth_typeTÚboolÚsupports_health_checkFÚsupports_visionÚsupports_vision_tool_messagesÚsupports_prompt_cache_keyÚfallback_modelsÚhostname)Údefault_factoryzdict[str, str]Údefault_headersNr   Úfixed_temperatureú
int | NoneÚdefault_max_tokensÚdefault_aux_model)Úvisionr.   r   c               ó   — dS )uÉ  Return a LIVE cheap-model id for auxiliary tasks, or "".

        ``default_aux_model`` is a hardcoded id in source, so it rots: when the
        provider retires that model every auxiliary call spends a round-trip
        404ing before the retry net catches it. Providers that publish a
        machine-readable recommendation should override this and query it, so
        the cheap tier tracks the upstream catalog instead of a constant a human
        has to remember to bump.

        Contract: cheap to call (implementations must cache â€” this runs on
        client-resolution paths), never raises, and returns "" when it has no
        answer so the caller falls through to ``default_aux_model``.
        r   r   )Úselfr.   s     r   Úresolve_aux_modelz!ProviderProfile.resolve_aux_modelh   s	   € ð ˆró    c                ój   — | j         r| j         S | j        rddlm}  || j        ¦  «        j         pdS dS )uà   Return the provider's base hostname for URL-based detection.

        Uses self.hostname if set explicitly, otherwise derives it from base_url.
        e.g. 'https://api.gmi-serving.com/v1' â†’ 'api.gmi-serving.com'
        r   )Úurlparser   )r'   r   Úurllib.parser4   )r0   r4   s     r   Úget_hostnamezProviderProfile.get_hostnamex   sQ   € ð Œ=ð 	!Ø”=Ð ØŒ=ð 	:Ø-Ð-Ð-Ð-Ð-Ð-Ø�8˜DœMÑ*Ô*Ô3Ð9°rÐ9Øˆrr2   Úmessagesúlist[dict[str, Any]]c                ó   — |S )zœProvider-specific message preprocessing.

        Called AFTER codex field sanitization, BEFORE developer role swap.
        Default: pass-through.
        r   )r0   r7   s     r   Úprepare_messagesz ProviderProfile.prepare_messages…   s	   € ð ˆr2   )Ú
session_idr;   ú
str | NoneÚcontextúdict[str, Any]c               ó   — i S )zrProvider-specific extra_body fields.

        Merged into the API kwargs extra_body. Default: empty dict.
        r   )r0   r;   r=   s      r   Úbuild_extra_bodyz ProviderProfile.build_extra_body�   s	   € ð ˆ	r2   )Úreasoning_configrA   údict | Noneú%tuple[dict[str, Any], dict[str, Any]]c               ó
   — i i fS )aþ  Provider-specific kwargs split between extra_body and top-level api_kwargs.

        Returns (extra_body_additions, top_level_kwargs).
        The transport merges extra_body_additions into extra_body, and
        top_level_kwargs directly into api_kwargs.

        This split exists because some providers put reasoning config in
        extra_body (OpenRouter: extra_body.reasoning) while others put it
        as top-level api_kwargs (Kimi: api_kwargs.reasoning_effort).

        Default: ({}, {}).
        r   )r0   rA   r=   s      r   Úbuild_api_kwargs_extrasz'ProviderProfile.build_api_kwargs_extras–   s   € ð$ �2ˆvˆr2   c                ó   — dS )u  Return a default vision model id for this provider, or None.

        Overrideable hook for providers that discover their vision default at
        runtime (e.g. from a live catalog) rather than pinning one in code.
        Keeps provider-specific vision discovery inside the provider's plugin
        instead of a name-check branch in shared vision resolution.

        Default: None (no provider-specific vision model â€” the caller falls
        back to the user's chat model or the aggregator chain).
        Nr   )r0   s    r   Údefault_vision_modelz$ProviderProfile.default_vision_modelª   s	   € ð ˆtr2   Úmodelc                ó   — | j         S )uð  Return the default max_tokens cap for *model*.

        Overrideable hook for providers that need per-model output caps â€”
        e.g. a relay that fronts several upstream backends, each with a
        different completion-token limit. The transport calls this when
        the user hasn't set an explicit max_tokens.

        Default: return self.default_max_tokens (the static profile field),
        ignoring the model name. Override in a subclass to vary the cap
        per-model.
        )r,   )r0   rH   s     r   Úget_max_tokenszProviderProfile.get_max_tokens·   s   € ð Ô&Ð&r2   g       @)r   r   ÚtimeoutrK   Úfloatúlist[str] | Nonec               óˆ  — |p| j         }| j        pd                     ¦   «         }|s|sdS |                     d¦  «        dz   }ddl}ddl}ddlm} |j         	                    |¦  «        }	|r|	 
                    dd|› �¦  «         |	 
                    d	d
¦  «         |	 
                    dt          ¦   «         ¦  «         | j                             ¦   «         D ]\  }
}|	 
                    |
|¦  «         Œ	  ||	|¬¦  «        5 }|                     |                     ¦   «                              ¦   «         ¦  «        }ddd¦  «         n# 1 swxY w Y   t#          |t$          ¦  «        r|n|                     dg ¦  «        }d„ |D ¦   «         S # t(          $ r,}t*                               d| j        |¦  «         Y d}~dS d}~ww xY w)uÜ  Fetch the live model list from the provider's models endpoint.

        Returns a list of model ID strings, or None if the fetch failed or
        the provider does not support live model listing.

        Resolution order for the endpoint URL:
          1. self.models_url  (explicit override â€” use when the models
             endpoint differs from the inference base URL, e.g. OpenRouter
             exposes a public catalog at /api/v1/models while inference is
             at /api/v1)
          2. base_url (caller override â€” user-configured model.base_url)
          3. self.base_url + "/models"  (standard OpenAI-compat fallback)

        The default implementation sends Bearer auth when api_key is given
        and forwards self.default_headers. Override to customise auth, path,
        response shape, or to return None for providers with no REST catalog.

        Callers must always fall back to the static _PROVIDER_MODELS list
        when this returns None.
        r   Nú/z/modelsr   )Úopen_credentialed_urlÚAuthorizationzBearer ÚAcceptzapplication/jsonz
User-Agent)rK   Údatac                óP   — g | ]#}t          |t          ¦  «        ¯d |v ¯|d          ‘Œ$S )Úid)Ú
isinstanceÚdict)Ú.0Úms     r   ú
<listcomp>z0ProviderProfile.fetch_models.<locals>.<listcomp>û   s0   € ÐPÐPÐP ­j¸½DÑ.AÔ.AÐPÀdÈaÀiÀi�A�d”GÀiÀiÀir2   zfetch_models(%s): %s)r   r   ÚstripÚrstripÚjsonÚurllib.requestÚhermes_cli.urllib_securityrP   ÚrequestÚRequestÚ
add_headerr   r)   ÚitemsÚloadsÚreadÚdecoderV   ÚlistÚgetr   ÚloggerÚdebugr   )r0   r   r   rK   Úeffective_baseÚurlr]   ÚurllibrP   ÚreqÚkÚvÚresprS   rc   Úexcs                   r   Úfetch_modelszProviderProfile.fetch_modelsÅ   s3  € ð6 "Ð2 T¤]ˆØŒÐ$ "×+Ò+Ñ-Ô-ˆØð 	9Ø!ð Ø�tØ ×'Ò'¨Ñ,Ô,¨yÑ8ˆCàˆˆˆØÐÐÐàDÐDÐDÐDÐDÐDàŒn×$Ò$ SÑ)Ô)ˆØð 	AØ�NŠN˜?Ð,?°gÐ,?Ð,?Ñ@Ô@Ð@Ø�Š�xÐ!3Ñ4Ô4Ð4ð 	�Š�|Õ%8Ñ%:Ô%:Ñ;Ô;Ð;ØÔ(×.Ò.Ñ0Ô0ð 	!ð 	!‰DˆAˆqØ�NŠN˜1˜aÑ Ô Ð Ð ð	Ø&Ð& s°GÐ<Ñ<Ô<ð 8ÀØ—z’z $§)¢)¡+¤+×"4Ò"4Ñ"6Ô"6Ñ7Ô7�ð8ð 8ð 8ñ 8ô 8ð 8ð 8ð 8ð 8ð 8ð 8øøøð 8ð 8ð 8ð 8å& t­TÑ2Ô2ÐL�D�D¸¿ºÀÈÑ8LÔ8LˆEØPÐP UÐPÑPÔPÐPøÝð 	ð 	ð 	Ý�LŠLÐ/°´¸CÑ@Ô@Ð@Ø�4�4�4�4�4øøøøð	øøøs<   Ã4F Ä:EÄ;F ÅEÅF ÅEÅ;F Æ
GÆ!F<Æ<G)r.   r!   r   r   ©r   r   )r7   r8   r   r8   )r;   r<   r=   r   r   r>   )rA   rB   r=   r   r   rC   )r   r<   )rH   r<   r   r+   )r   r<   r   r<   rK   rL   r   rM   )"Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú__annotations__r   r   r   r   r   r   r   r   r    r"   r#   r$   r%   r&   r'   r   rW   r)   r*   r,   r-   r1   r6   r:   r@   rE   rG   rJ   rs   r   r2   r   r   r   &   s{  € € € € € € àKÐKð €I€I�IØ&€HÐ&Ð&Ð&Ñ&Ø€GÐÐÐÑð €LÐÐÐÑØ€KÐÐÐÑØ€JÐÐÐÑð €HÐÐÐÑØ€HÐÐÐÑØ€JÐÐÐÑØ€IÐÐÐÑØ"&ÐÐ&Ð&Ð&Ñ&ð "€OÐ!Ð!Ð!Ñ!ð +/Ð!Ð.Ð.Ð.Ñ.ð ',ÐÐ+Ð+Ð+Ñ+ð
  €OÐÐÐÑð €HÐÐÐÑð ', e¸DÐ&AÑ&AÔ&A€OÐAÐAÐAÑAð "ÐÐ!Ð!Ð!Ñ!Ø%)ÐÐ)Ð)Ð)Ñ)à
ð ð ð ð ñ ð 38ð ð ð ð ð ð ð ð ð ð ðð ð ð ð +/ðð ð ð ð ð ð )-ðð ð ð ð ð ð(ð ð ð ð'ð 'ð 'ð 'ð" #Ø#Øð9ð 9ð 9ð 9ð 9ð 9ð 9ð 9r2   r   rt   )rx   Ú
__future__r   ÚloggingÚdataclassesr   r   Útypingr   Ú	getLoggerru   ri   ÚobjectÚOMIT_TEMPERATUREr   r   r   r2   r   ú<module>r�      sÒ   ðð	ð 	ð #Ð "Ð "Ð "Ð "Ð "à €€€Ø (Ð (Ð (Ð (Ð (Ð (Ð (Ð (Ø Ð Ð Ð Ð Ð à	ˆÔ	˜8Ñ	$Ô	$€ð �6‘8”8Ð ðð ð ð ð ðWð Wð Wð Wð Wñ Wô Wñ „ðWð Wð Wr2   