
    iNB                       U d Z ddlmZ ddlZddlmZ ddlmZmZm	Z	m
Z
mZ  ej        e          Z ed           G d d	                      Zi d
 edddd          d eddd          d eddd          d edddd          d edddd          d edd !          d" ed#d$!          d% edd&d'(          d) edd*+          d, ed#d-+          d. ed#d/+          d0 edd1+          d2 edd3+          d4 edd5          d6 eddd78          d9 eddd:8          d; eddd<8           eddd=8           edd>d?@           eddA+           eddBdC@          dDZdEedF<   e G dG dH                      Zi dId
dJd%dKd%dLd%dMd%dNdOdPdOdQd)dRd)dSd)dTd)dUd.dVd.dWd"dXd"dYddZdi d[dd\d4d]d4d^d4d_d6d`d6dad9dbd9dcd;ddd;ded;dfd0dgd2dhd2did2djd2dkdldldldmdmdndndodododpdqdqdqdqdrZdsedt<   dudvdwdxdydzZdsed{<   d|d#dd}Zdsed~<   ddZddZddZddZdddZddZddZddZ	 	 dddZdS )u  
Single source of truth for provider identity in Hermes Agent.

Two data sources, merged at runtime:

1. **models.dev catalog** — 109+ providers with base URLs, env vars, display
   names, and full model metadata (context, cost, capabilities).  This is
   the primary database.

2. **Hermes overlays** — transport type, auth patterns, aggregator flags,
   and additional env vars that models.dev doesn't track.  Small dict,
   maintained here.

3. **User config** (``providers:`` section in config.yaml) — user-defined
   endpoints and overrides.  Merged on top of everything else.

Other modules import from this file.  No parallel registries.
    )annotationsN)	dataclass)AnyDictListOptionalTupleT)frozenc                  h    e Zd ZU dZ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S )HermesOverlayz?Hermes-specific provider metadata layered on top of models.dev.openai_chatstr	transportFboolis_aggregatorapi_key	auth_type Tuple[str, ...]extra_env_vars base_url_overridebase_url_env_varN)__name__
__module____qualname____doc__r   __annotations__r   r   r   r   r   r       2/root/.hermes/hermes-agent/hermes_cli/providers.pyr   r       s         II"I""""MI&(N((((r   r   
openrouterr   )OPENAI_API_KEYOPENROUTER_BASE_URL)r   r   r   r   nousoauth_device_codez)https://inference-api.nousresearch.com/v1)r   r   r   openai-codexcodex_responsesoauth_externalz%https://chatgpt.com/backend-api/codexz
qwen-oauthzhttps://portal.qwen.ai/v1HERMES_QWEN_BASE_URL)r   r   r   r   copilot-acpexternal_processzacp://copilotCOPILOT_ACP_BASE_URLzgithub-copilot)COPILOT_GITHUB_TOKENGH_TOKEN)r   r   	anthropicanthropic_messages)ANTHROPIC_TOKENCLAUDE_CODE_OAUTH_TOKENzai)GLM_API_KEYZAI_API_KEYZ_AI_API_KEYGLM_BASE_URL)r   r   r   zkimi-for-codingKIMI_BASE_URL)r   r   minimaxMINIMAX_BASE_URLz
minimax-cnMINIMAX_CN_BASE_URLdeepseekDEEPSEEK_BASE_URLalibabaDASHSCOPE_BASE_URLvercel)r   r   opencodeOPENCODE_ZEN_BASE_URL)r   r   r   zopencode-goOPENCODE_GO_BASE_URLkiloKILOCODE_BASE_URLHF_BASE_URLzhttps://api.x.ai/v1XAI_BASE_URL)r   r   r   XIAOMI_BASE_URLzhttps://api.arcee.ai/api/v1ARCEE_BASE_URL)huggingfacexaixiaomiarceezDict[str, HermesOverlay]HERMES_OVERLAYSc                      e Zd ZU dZded<   ded<   ded<   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S )ProviderDefu9   Complete provider definition — merged from all sources.r   idnamer   r   api_key_env_varsr   base_urlr   Fr   r   r   r   docsourceN)r   r   r   r   r   rT   r   r   r   rU   rV   r   r   r    rP   rP      s         CCGGGIIINNN%%%%HMICMMMMFr   rP   openaiglmzz-aizz.aizhipuzx-airK   zx.aikimizkimi-codingzkimi-coding-cnmoonshotzminimax-china
minimax_cnclaudezclaude-codecopilotgithubzgithub-copilot-acpz
ai-gateway	aigatewayzvercel-ai-gatewayzopencode-zenzengozopencode-go-subkilocodez	kilo-codezkilo-gatewayz	deep-seek	dashscopealiyunqwenzalibaba-cloudhfrJ   rL   rM   lmstudiozollama-cloudlocal)zhugging-facezhuggingface-hubmimozxiaomi-mimozarcee-aiarceeairh   z	lm-studio	lm_studioollamavllmllamacppz	llama.cppz	llama-cppzDict[str, str]ALIASESzNous PortalzOpenAI CodexzGitHub Copilot ACPzXiaomi MiMozLocal endpoint)r$   r&   r*   rL   ri   _LABEL_OVERRIDESchat_completions)r   r0   r'   TRANSPORT_TO_API_MODErR   r   returnc                    |                                                                  }t                              ||          S )zResolve aliases and normalise casing to a canonical provider id.

    Returns the canonical id string.  Does *not* validate that the id
    corresponds to a known provider.
    )striplowerrp   get)rR   keys     r    normalize_providerrz     s1     **,,



C;;sC   r   Optional[ProviderDef]c                   t          |           }	 ddlm}  ||          }n# t          $ r d}Y nw xY wt                              |          }||r|j        nd}|r|j        nd}|r|j        nd}|r|j	        nd}|r|j
        nd}	t          |j                  }
|r*|j        r#|j        D ]}||
vr|
                    |           t          ||j        |t#          |
          |	p|j        ||||j        d	
  
        S |Ot          |t(                              ||          |j        |j        |j
        |j	        |j        |j        d
	  	        S dS )aI  Look up a provider by id or alias, merging all data sources.

    Resolution order:
      1. Hermes overlays (for providers not in models.dev: nous, openai-codex, etc.)
      2. models.dev catalog + Hermes overlay
      3. User-defined providers from config (TODO: Phase 4)

    Returns a fully-resolved ProviderDef or None.
    r   get_provider_infoNr   Fr   r   
models.dev)
rQ   rR   r   rS   rT   r   r   r   rU   rV   hermes)	rQ   rR   r   rS   rT   r   r   r   rV   )rz   agent.models_devr~   	ExceptionrN   rx   r   r   r   r   r   listenvr   appendrP   rR   tupleapirU   rq   )rR   	canonical_mdev_provider	mdev_infooverlayr   is_aggauthbase_url_envr   env_varsevs               r    get_providerr   !  s    #4((IHHHHHH"N9--		   			 !!),,G)0CG%%m	*1<&&u$+:w  3:Bw//9@HG55b 	&& 	(w- 	(, ( (X%%OOB'''"8__&7)-) 
 
 
 	
 !%%i;;'$3.$5!/'

 

 

 
	
 4s   # 22provider_idc                    t          |           }|t          v rt          |         S t          |          }|r|j        S |S )z1Get a human-readable display name for a provider.)rz   rq   r   rR   )r   r   pdefs      r    	get_labelr   c  sM    ";//I $$$	** 	""D yr   providerr   c                6    t          |           }|r|j        ndS )z:Return True when the provider is a multi-model aggregator.F)r   r   )r   r   s     r    r   r   u  s"    !!D!%0450r   r   rT   c                    t          |           }| t                              |j        d          S |rH|                    d                                          }|                    d          sd|v rdS d|v rdS dS )	u   Determine the API mode (wire protocol) for a provider/endpoint.

    Resolution order:
      1. Known provider → transport → TRANSPORT_TO_API_MODE.
      2. URL heuristics for unknown / custom providers.
      3. Default: 'chat_completions'.
    Nrr   /z
/anthropiczapi.anthropic.comr0   zapi.openai.comr'   )r   rs   rx   r   rstriprw   endswith)r   rT   r   	url_lowers       r    determine_api_moder   {  s     !!D$((9KLLL  %OOC((..00	l++ 	(/Bi/O/O''y(($$r   user_configDict[str, Any]c           
        |rt          |t                    sdS |                    |           }t          |t                    sdS |                    dd          p| }|                    dd          p-|                    dd          p|                    dd          pd}|                    dd          pd}|                    dd	          pd	}g }|r|                    |           t	          | ||t          |          |d
dd          S )zResolve a provider from the user's config.yaml ``providers:`` section.

    Args:
        name: Provider name as given by the user.
        user_config: The ``providers:`` dict from config.yaml.

    Returns:
        ProviderDef if found, else None.
    NrR   r   r   urlrT   key_envr   r   Fr   user-configrQ   rR   r   rS   rT   r   r   rV   )
isinstancedictrx   r   rP   r   )rR   r   entrydisplay_nameapi_urlr   r   r   s           r    resolve_user_providerr     s(     jd;; tOOD!!EeT"" t 99VR((0DLiir""]eiir&:&:]eii
TV>W>W][]Gii	2&&,"G		+}55FIH !   x	 	 	 	r   r   c                |    d|                                                                                      dd          z   S )zBuild a canonical slug for a custom_providers entry.

    Matches the convention used by runtime_provider and credential_pool
    (``custom:<normalized-name>``).  Centralised here so all call-sites
    produce identical slugs.
    zcustom: -)rv   rw   replace)r   s    r    custom_provider_slugr     s7     |))++1133;;CEEEEr   custom_providersOptional[List[Dict[str, Any]]]c                N   |rt          |t                    sdS | pd                                                                }|sdS |D ]}t          |t                    s|                    d          pd                                }|                    dd          p-|                    dd          p|                    dd          pd                                }|r|st          |          }||                                |hvrt          ||dd|d	d
d          c S dS )zIResolve a provider from the user's config.yaml ``custom_providers`` list.Nr   rR   rT   r   r   r   r   Fr   r   r   )r   r   rv   rw   r   rx   r   rP   )rR   r   	requestedr   r   r   slugs          r    resolve_custom_providerr     sl   
  :.>#E#E t""$$**,,I t! 
 
%&& 			&))/R6688IIj"%% yy##yy## 
%'' 	  	7 	#L11\//114888# 	
 	
 	
 		
 		
 		
 4r   user_providersOptional[Dict[str, Any]]c                   t          |           }t          |          }||S |rLt          ||          }||S t          |                                                                 |          }||S t          | |          }||S 	 ddlm}  ||          }|$t          ||j	        d|j
        |j        d          S n# t          $ r Y nw xY wdS )u  Full resolution chain: built-in → models.dev → user config.

    This is the main entry point for --provider flag resolution.

    Args:
        name: Provider name or alias.
        user_providers: The ``providers:`` dict from config.yaml (optional).
        custom_providers: The ``custom_providers:`` list from config.yaml (optional).

    Returns:
        ProviderDef if found, else None.
    Nr   r}   r   r   )rQ   rR   r   rS   rT   rV   )rz   r   r   rv   rw   r   r   r~   rP   rR   r   r   r   )	rR   r   r   r   r   	user_pdefcustom_pdefr   r   s	            r    resolve_provider_fullr     s&   " #4((I 	""D  ))^DD	 )$**,,*<*<*>*>OO	  *$0@AAKHHHHHH"N9--	 ^'!*"#    !     4s   6B> >
C
C)rR   r   rt   r   )rR   r   rt   r{   )r   r   rt   r   )r   r   rt   r   )r   )r   r   rT   r   rt   r   )rR   r   r   r   rt   r{   )r   r   rt   r   )rR   r   r   r   rt   r{   )NN)rR   r   r   r   r   r   rt   r{   )r   
__future__r   loggingdataclassesr   typingr   r   r   r   r	   	getLoggerr   loggerr   rN   r   rP   rp   rq   rs   rz   r   r   r   r   r   r   r   r   r   r   r    <module>r      s    & # " " " " "  ! ! ! ! ! ! 3 3 3 3 3 3 3 3 3 3 3 3 3 3		8	$	$ $       d---*.	  d- MM%E  d- MM#"A  d-" --"5/	  #d-. ==#$)/	  /d-: mm;  ;d-B &E  Cd-J 
==E'  Kd-T }}(  Ud-\ }}&+  ]d-d --&.  ed-l ,  md-t }}-  ud-| mm  }d-D 0  Ed-N ==/  Od-X MM,  Yd-b !=&  
 =/'  
 m*   ]7)  d- d- d- d d d dT        &RlR
 
5R ER ER UR ER ER R  $!R" '#R$ !%R* \+R, ,-R2 k3R4 ;5R: ;R< =R R> -?RD (ERF GRH IRN JORP 
:QRV 	-WRX }YR^ _R` aRb FcRh iRn oRp iqRr IsRt YuRz 	-{R R| "$   cR R R R R R Rt "'$ $      &.() )     ! ! ! !? ? ? ?D   $1 1 1 1    2$ $ $ $NF F F F) ) ) )\ 047;8 8 8 8 8 8 8r   