
    i                        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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)Anyc                  @   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<    ee          Zded<   dZded<   dZded<   d	Zded<   d3dZd4d!Zdd"d5d'Zdd(d6d,Zdd-d.d7d2ZdS )8ProviderProfileuA   Base provider profile — subclass or instantiate with overrides.strnamechat_completionsapi_mode tuplealiases display_namedescription
signup_urlenv_varsbase_url
models_urlapi_key	auth_typefallback_modelshostname)default_factoryzdict[str, str]default_headersNr   fixed_temperaturez
int | Nonedefault_max_tokensdefault_aux_modelreturnc                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.parser"   )selfr"   s     3/home/piyush/.hermes/hermes-agent/providers/base.pyget_hostnamezProviderProfile.get_hostnameC   sQ     = 	!= = 	:------8DM**39r9r    messageslist[dict[str, Any]]c                    |S )zProvider-specific message preprocessing.

        Called AFTER codex field sanitization, BEFORE developer role swap.
        Default: pass-through.
        r   )r$   r(   s     r%   prepare_messagesz ProviderProfile.prepare_messagesP   s	     r'   )
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   )r$   r,   r.   s      r%   build_extra_bodyz ProviderProfile.build_extra_bodyX   s	     	r'   )reasoning_configr2   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   )r$   r2   r.   s      r%   build_api_kwargs_extrasz'ProviderProfile.build_api_kwargs_extrasa   s    $ 2vr'   g       @)r   timeoutr7   floatlist[str] | Nonec               X   | j         pd                                }|s&| j        sdS | j                            d          dz   }ddl}ddl}|j                            |          }|r|                    dd|            |                    dd	           | j	        
                                D ]\  }}|                    ||           	 |j                            ||
          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. 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   AuthorizationzBearer Acceptzapplication/json)r7   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PdaiiAdGiiir'   zfetch_models(%s): %s)r   stripr   rstripjsonurllib.requestrequestRequest
add_headerr   itemsurlopenloadsreaddecoderA   listget	Exceptionloggerdebugr
   )r$   r   r7   urlrH   urllibreqkvrespr>   rM   excs                r%   fetch_modelszProviderProfile.fetch_modelsu   s   2 $"++-- 	8= t-&&s++i7Cn$$S)) 	ANN?,?g,?,?@@@x!3444(..00 	! 	!DAqNN1a    	''W'== 8zz$))++"4"4"6"6778 8 8 8 8 8 8 8 8 8 8 8 8 8 8&tT22LDD8L8LEPPUPPPP 	 	 	LL/C@@@44444	s<   E3 ):D/#E3 /D33E3 6D37;E3 3
F)=!F$$F))r    r	   )r(   r)   r    r)   )r,   r-   r.   r   r    r/   )r2   r3   r.   r   r    r4   )r   r-   r7   r8   r    r9   )__name__
__module____qualname____doc____annotations__r   r   r   r   r   r   r   r   r   r   r   r   rB   r   r   r   r   r&   r+   r1   r6   r^   r   r'   r%   r   r      s        KK III&H&&&&G LKJ HHJI
  O H ',eD&A&A&AOAAAA "!!!!%)))))
            +/      )-     . #	0 0 0 0 0 0 0 0r'   r   )rb   
__future__r   loggingdataclassesr   r   typingr   	getLoggerr_   rU   objectOMIT_TEMPERATUREr   r   r'   r%   <module>rk      s   	 	 # " " " " "  ( ( ( ( ( ( ( (      		8	$	$ 688  L L L L L L L L L Lr'   