+
    iB              	        a  0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RI	H
t
 ^ RIHtHt Rt] R2tRt. ROt. ROt]t]t. ROtR]R&   / R. RObR. RObRR.bR. RObR. RObR . RObR#. RObR&. RObR'. RObR(. RObR). RObR,R-R..bR/. R0NRNRNR1NR2NRNR3NR4NRNRNR5NR6NR7NR*NR8NR9NR+NR:NR;NR<NR=NR>NR?NR@NRANRBNRCNRDNR!NR"NRENR$NR%NRFNRGNRHNbRI. RObRJ. RObRN. RObRO. RObRP. ER O/CtRQ]RR&   / RSRTbRRUbRRVbRRWbRRXbRRYbR RZbR#R[bR'R\bR(R]bR)R^bR,R_bR/R`bRIRabRJRbbRNRcbRORdbRPReRfRg/Ct/ RhRbRiR bRjR bRkR bRlR bRmRbRnRbRoRbRpRbRqRbRrRbRsRbRtRbRuRbRvR#bR&R#bRwR(b/ RxR(bRyR)bRzR)bR{R,bR|R/bR}R/bR~RIbRRIbRRJbRRJbRRJbRRNbRRNbRRNbRRObRRObRRObCRRORRPRRPRRP/CtR R ltR R lt/ tR]R&   R R ltR R ltERR R lltERRR/R R lllt R R lt!R R lt"R R lt#]$! ]PK                  4       4      ]$! ]PK                  4       4      ,          RSRf0,          t&R]R&   R R lt'R R lt(R R lt)R R lt*R R lt+R R lt,R R lt-R R lt.R R lt/R R lt0ERR R llt1R R lt2R R lt3R R lt4R R lt5ERR R llt6R R lt7ERR R llt8/ RKRbRRbRRbRRbRLRbRMRbRRbRRbRRbRR2bRRbRR2bRRbRRbRRbRRbR	RbR
RRR/Ct9ERR R llt:RRRR/R R llt;R R lt<R R lt=RRRR/R R llt>R R lt?R R lt@RRRR/R R lltAERR R lltBERR R lltCERR R lltDRRRR/R R lltER# (  u   
Canonical model catalogs and lightweight validation helpers.

Add, remove, or reorder entries here — both `hermes setup` and
`hermes` provider-selection will pick up the change automatically.
)annotationsN)get_close_matches)AnyOptionalzhttps://api.githubcopilot.com/modelszvscode/1.104.1anthropic/claude-opus-4.6anthropic/claude-sonnet-4.6anthropic/claude-sonnet-4.5anthropic/claude-haiku-4.5list[tuple[str, str]]OPENROUTER_MODELSnousopenai-codexgpt-5.3-codexgpt-5.2-codexgpt-5.1-codex-minigpt-5.1-codex-maxcopilot-acpcopilotgpt-5.4
gpt-5-minigpt-4.1gpt-4ogpt-4o-miniclaude-opus-4.6claude-sonnet-4.6claude-sonnet-4.5claude-haiku-4.5geminizaiglm-5glm-4.7kimi-coding	kimi-k2.5kimi-k2-thinkingmoonshotminimax
minimax-cn	anthropicclaude-opus-4-6claude-sonnet-4-6deepseekzdeepseek-chatzdeepseek-reasoneropencode-zenzgpt-5.4-prozgpt-5.3-codex-sparkzgpt-5.2zgpt-5.1zgpt-5.1-codexgpt-5zgpt-5-codexz
gpt-5-nanozclaude-opus-4-5zclaude-opus-4-1zclaude-sonnet-4-5zclaude-sonnet-4zclaude-haiku-4-5zclaude-3-5-haikuzgemini-3.1-prozgemini-3-prozgemini-3-flashminimax-m2.7minimax-m2.5zminimax-m2.5-freezminimax-m2.1zglm-4.6zkimi-k2zqwen3-coderz
big-pickleopencode-go
ai-gatewayopenai/gpt-5openai/gpt-4.1openai/gpt-4.1-minikilocodealibabahuggingfacezdict[str, list[str]]_PROVIDER_MODELS
openrouter
OpenRouterzOpenAI CodexzGitHub Copilot ACPzNous PortalzGitHub CopilotzGoogle AI Studioz
Z.AI / GLMzKimi / MoonshotMiniMaxzMiniMax (China)	AnthropicDeepSeekzOpenCode ZenzOpenCode Goz
AI Gatewayz	Kilo CodezAlibaba Cloud (DashScope)zHugging FacecustomzCustom endpointopenaiglmzz-aizz.aizhipugithubzgithub-copilotzgithub-modelszgithub-modelzgithub-copilot-acpzcopilot-acp-agentgooglezgoogle-geminizgoogle-ai-studiokimizminimax-china
minimax_cnclaudezclaude-codez	deep-seekopencodezengozopencode-go-sub	aigatewayvercelzvercel-ai-gatewaykiloz	kilo-codezkilo-gateway	dashscopealiyunqwenzalibaba-cloudhfzhugging-facezhuggingface-hubc                   V ^8  d   QhRR/#    return	list[str] )formats   "./home/ubuntu/hermes-agent/hermes_cli/models.py__annotate__rY   L  s     1 19 1    c                 B    \          U Uu. uF  w  rV NK	  	  upp # u upp i )z,Return just the OpenRouter model-id strings.)r   )mid_s     rX   	model_idsr^   L  s    /0/FCC/000s   c                   V ^8  d   QhRR/# rR   rV   )rW   s   "rX   rY   rY   Q  s      Y rZ   c                 j    . p \          F&  w  rT P                  V'       d	   V RV R2MT4       K(  	  V # )zEReturn display labels like 'anthropic/claude-opus-4.6 (recommended)'.z ())r   append)labelsr\   descs      rX   menu_labelsre   Q  s5    F&	4RvQ'S9 'MrZ   z$dict[str, dict[str, dict[str, str]]]_pricing_cachec                    V ^8  d   QhRRRR/# )rS   per_token_strstrrT   rV   )rW   s   "rX   rY   rY   a  s      # # rZ   c                z     \        V 4      pT^ 8X  d   R# TR,          pRTR 2#   \        \        3 d     R# i ; i)u  Convert a per-token price string to a human-friendly $/Mtok string.

Always uses 2 decimal places so that prices align vertically when
right-justified in a column (the decimal point stays in the same position).

Examples:
    "0.000003"   → "$3.00"      (per million tokens)
    "0.00003"    → "$30.00"
    "0.00000015" → "$0.15"
    "0.0000001"  → "$0.10"
    "0.00018"    → "$180.00"
    "0"          → "free"
?freei@B $z.2f)float	TypeError
ValueError)rh   valper_ms   &  rX   _format_price_per_mtokrs   a  sM    M" ax)OEuSk? z" s   % ::c                    V ^8  d   QhRRRR/# )rS   pricingzdict[str, str] | NonerT   ri   rV   )rW   s   "rX   rY   rY   y  s     ( ("7 (C (rZ   c                   V '       g   R# V P                  RR4      pV P                  RR4      pV'       g   V'       g   R# \        V4      p\        V4      pVR8X  d
   VR8X  d   R# V P                  RR4      pV'       d   \        V4      MRpW48X  d   V'       g   V R2# RV 2RV 2.pV'       d"   VR	8w  d   Wc8w  d   VP                  R
V 24       RP                  V4      R,           # )u~   Build a compact pricing label like 'in $3 · out $15 · cache $0.30/Mtok'.

Returns empty string when pricing is unavailable.
 prompt
completionrl   input_cache_readz/Mtokzin zout rk   zcache u    · )getrs   rb   join)ru   prompt_pricecompletion_priceinpout
cache_read	cache_strpartss   &       rX   format_pricing_labelr   y  s    
 ;;x,L{{<4 0
 
.C
 !1
2C
f}/4J6@&z2bI
z)e}3%[D,'EY#%)*:vi[)*;;u''rZ   c          
     ,    V ^8  d   QhRRRRRRRRRR	/# )
rS   modelsr   pricing_mapdict[str, dict[str, str]]current_modelri   indentrT   rU   rV   )rW   s   "rX   rY   rY     s:     ; ;!;*; ; 	;
 ;rZ   c                   V '       g   . # . pRpV  F  w  rgWb8H  pVP                  V4      p	V	'       di   \        V	P                  RR4      4      p
\        V	P                  RR4      4      pV	P                  RR4      pV'       d   \        V4      MRpV'       d   RpMRRRrp
VP                  WjWV34       K  	  \        R V 4       4      ^,           p\        \        R V 4       ^R	7      \        R
 V 4       ^R	7      ^4      pV'       d   \        \        R V 4       ^R	7      ^4      M^ p. pV'       dk   VP                  V RRV 2 RRRV 2 RRRV 2 RRRV 2 R2	4       VP                  V RV,           RRV,           RRV,           RRV,           24       MXVP                  V RRV 2 RRRV 2 RRRV 2 R24       VP                  V RV,           RRV,           RRV,           24       V Fv  w  rjrpV'       d   RMRpV'       d3   VP                  V VRV 2 RV
RV 2 RVRV 2 RVRV 2 V 2	4       KM  VP                  V VRV 2 RV
RV 2 RVRV 2 V 24       Kx  	  V# )zBuild a column-aligned model+pricing table for terminal display.

Returns a list of pre-formatted lines ready to print.
*models* is ``[(model_id, description), ...]``.
Frx   rw   ry   rz   Tc              3  F   "   T F  p\        V^ ,          4      x  K  	  R# 5i)    Nlen.0rs   & rX   	<genexpr>-format_model_pricing_table.<locals>.<genexpr>  s     +d3qt99ds   !c              3  f   "   T F'  q^,          '       g   K  \        V^,          4      x  K)  	  R# 5i)   Nr   r   s   & rX   r   r     "     -1!YS1YY   11)defaultc              3  f   "   T F'  q^,          '       g   K  \        V^,          4      x  K)  	  R# 5i)rS   Nr   r   s   & rX   r   r     r   r   c              3  f   "   T F'  q^,          '       g   K  \        V^,          4      x  K)  	  R# 5i)   Nr   r   s   & rX   r   r     r   r   Model< In>z  OutCachez  /Mtok-u     ← current)r{   rs   rb   max)r   r   r   r   rows	has_cacher\   _descis_curpr   r   r   cachename_col	price_col	cache_collinesmarkers   &&&&               rX   format_model_pricing_tabler     s    	 35DI
%OOC (x)<=C(|R)@AC126J:D*:6"E 	 "beCSs623  +d++a/H--q9--q9	I 
 --q9	   E x(|4Ad1YK-5H5QRS\R]P]J^^`ahijktjuhu`vv}~xh/qy0AC)OCTTVWZ]fWfVghix(|4Ad1YK-5H5QRS\R]P]J^^efgxh/qy0AC)OCTUV(,$#f$*LLF8C(|#4Ac!I;5Gr#aPY{]I[[]^cdefoepcp]qrxqyz{LLF8C(|#4Ac!I;5Gr#aPY{]I[\b[cde )- LrZ   force_refreshFc          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )rS   api_keyz
str | Nonebase_urlri   timeoutrn   r   boolrT   r   rV   )rW   s   "rX   rY   rY     s:     - --- -
 - -rZ   c          
     4   T;'       g    RP                  R4      pV'       g   V\        9   d   \        V,          # VP                  R4      R,           pRR/pV '       d	   RV  2VR&    \        P                  P	                  WVR7      p\        P                  P                  WrR	7      ;_uu_ 4       p\        P                  ! VP                  4       P                  4       4      p	R
R
R
4       / p
X	P                  R. 4       F  pTP                  R4      pTP                  R4      pT'       g   K/  \        T\        4      '       g   KG  R\        TP                  RR4      4      R\        TP                  RR4      4      /pTP                  R4      '       d   \        TR,          4      TR&   TP                  R4      '       d   \        TR,          4      TR&   YT&   K  	  T
\        T&   T
#   + '       g   i     EL; i  \         d    / \        T&   / u # i ; i)zFetch ``/v1/models`` and return ``{model_id: {prompt, completion}}`` pricing.

Results are cached per *base_url* so repeated calls are free.
Works with any OpenRouter-compatible endpoint (OpenRouter, Nous Portal).
rw   /z
/v1/modelsAcceptzapplication/jsonBearer Authorizationheadersr   Ndataidru   rx   ry   rz   input_cache_write)rstriprf   urllibrequestRequesturlopenjsonloadsreaddecode	Exceptionr{   
isinstancedictri   )r   r   r   r   	cache_keyurlr   reqresppayloadresultitemr\   ru   entrys   &&&$           rX   fetch_models_with_pricingr     s    R'',IY.8i((


3
,
.C');<G%,WI#6 nn$$S$:^^##C#99Tjj!3!3!56G : )+FFB'hhtn((9%3:gt,,#gkk(B78c'++lB"?@%E {{-..,/8J0K,L(){{.//-09L1M-N)*3K ( !'N9M- :99 $&y!	s1   )AG> 13G*$G> *G;	5G> ;G> >HHc                   V ^8  d   QhRR/# rS   rT   ri   rV   )rW   s   "rX   rY   rY      s     7 7S 7rZ   c                 L    \         P                  ! RR4      P                  4       # )z1Best-effort OpenRouter API key for pricing fetch.OPENROUTER_API_KEYrw   )osgetenvstriprV   rZ   rX   _resolve_openrouter_api_keyr      s    99)2.4466rZ   c                   V ^8  d   QhRR/# )rS   rT   tuple[str, str]rV   )rW   s   "rX   rY   rY     s     	 	? 	rZ   c                      ^ RI Hp  V ! 4       pV'       d%   VP                  RR4      VP                  RR4      3#  R#   \         d     R# i ; i)zIReturn ``(api_key, base_url)`` for Nous Portal pricing, or empty strings.) resolve_nous_runtime_credentialsr   rw   r   )rw   rw   )hermes_cli.authr   r{   r   )r   credss     rX   !_resolve_nous_pricing_credentialsr     s[    D02IIi,eii
B.GHH  O  Os   > #> AAc                    V ^8  d   QhRRRR/# )rS   providerri   rT   r   rV   )rW   s   "rX   rY   rY     s      s /H rZ   c                    \        V 4      pVR8X  d   \        \        4       RR7      # VR8X  dO   \        4       w  r#V'       d;   VP	                  R4      pVP                  R4      '       d   VRR p\        VVR7      # / # )	zEReturn live pricing for providers that support it (openrouter, nous).r9   https://openrouter.ai/api)r   r   r   r   /v1N)normalize_providerr   r   r   r   endswith)r   
normalizedr   r   strippeds   &    rX   get_pricing_for_providerr     s    #H-J\!(/10
 	
 V=?  s+H  ''#CR=,!  IrZ   set[str]_KNOWN_PROVIDER_NAMESc                   V ^8  d   QhRR/# )rS   rT   zlist[dict[str, str]]rV   )rW   s   "rX   rY   rY   0  s     + +"6 +rZ   c                    . ROp / p\         P                  4        F&  w  r#VP                  V. 4      P                  V4       K(  	  . pV  F  p\        P                  WU4      pVP                  V. 4      pRp ^ RIHp	Hp
 VR8X  d/   \        4       ;'       g    Rp\        VP                  4       4      pMaVR8X  d   V
! \        P                  ! RR4      4      pM<V	! V4      p\        VP                  R4      ;'       g    VP                  R4      4      p VP                  R	VR
VRVRV/4       K  	  V#   \         d     L,i ; i)zReturn info about all providers the user could use with ``provider:model``.

Each dict has ``id``, ``label``, and ``aliases``.
Checks which providers have valid credentials configured.
r9   r>   F)get_auth_statushas_usable_secretrw   r   	logged_in
configuredr   labelaliasesauthenticated)r9   r   r   r   r   r   r7   r   r"   r&   r'   r5   r(   r6   r,   r0   r1   r+   r>   )_PROVIDER_ALIASESitems
setdefaultrb   _PROVIDER_LABELSr{   r   r   r   _get_custom_base_urlr   r   r   r   r   )_PROVIDER_ORDERaliases_foralias	canonicalr   pidr   
alias_list	has_credsr   r   custom_base_urlstatuss                rX   list_available_providersr  0  s7   O )+K-335y"-44U; 6 F $$S. __S"-
		Jh"6"8">">B !6!6!89	$-bii8Lb.QR	(- K!8!T!TFJJ|<TU	 	#UzY	
 	# . M  		s*   6D3D33$D3$D3=D33E Ec               $    V ^8  d   QhRRRRRR/# )rS   rawri   current_providerrT   r   rV   )rW   s   "rX   rY   rY   ^  s!     !( !(3 !(# !(/ !(rZ   c                   V P                  4       pVP                  R4      pV^ 8  d   VRV P                  4       P                  4       pW#^,           R P                  4       pV'       d   V'       d{   V\        9   dp   VR8X  d\   RV9   dU   VP                  R4      pVRV P                  4       pWV^,           R P                  4       pV'       d   V'       d   RV 2V3# \	        V4      V3# W3# )u<  Parse ``/model`` input into ``(provider, model)``.

Supports ``provider:model`` syntax to switch providers at runtime::

    openrouter:anthropic/claude-sonnet-4.5  →  ("openrouter", "anthropic/claude-sonnet-4.5")
    nous:hermes-3                           →  ("nous", "hermes-3")
    anthropic/claude-sonnet-4.5             →  (current_provider, "anthropic/claude-sonnet-4.5")
    gpt-5.4                                 →  (current_provider, "gpt-5.4")

The colon is only treated as a provider delimiter if the left side is a
recognized provider name or alias.  This avoids misinterpreting model names
that happen to contain colons (e.g. ``anthropic/claude-3.5-sonnet:beta``).

Returns ``(provider, model)`` where *provider* is either the explicit
provider from the input or *current_provider* if none was specified.
:Nr>   zcustom:)r   findlowerr   r   )	r  r  r   colonprovider_part
model_partsecond_coloncustom_nameactual_models	   &&       rX   parse_model_inputr  ^  s    " yy{HMM#Eqy %(..0668aij)//1
ZM=R,R (SJ->)s3(,7==?)*:*;<BBD<%k]3\BB&}5zBB''rZ   c                   V ^8  d   QhRR/# r   rV   )rW   s   "rX   rY   rY     s     
 
c 
rZ   c                      ^ RI Hp  V ! 4       pVP                  R/ 4      p\        V\        4      '       d*   \        VP                  RR4      4      P                  4       #  R#   \         d     R# i ; i)z2Get the custom endpoint base_url from config.yaml.)load_configmodelr   rw   )hermes_cli.configr  r{   r   r   ri   r   r   )r  config	model_cfgs      rX   r  r    sn    1JJw+	i&&y}}Z45;;== '   s   AA# #A21A2c                    V ^8  d   QhRRRR/# )rS   r   Optional[str]rT   r   rV   )rW   s   "rX   rY   rY     s     % %- %<Q %rZ   c                    \        V 4      pVR8X  d   \        \        4      # \        V4      pV'       d   V Uu. uF  q3R3NK  	  up# \        P                  V. 4      pV Uu. uF  q3R3NK  	  up# u upi u upi )zReturn ``(model_id, description)`` tuples for a provider's model list.

Tries to fetch the live model list from the provider's API first,
falling back to the static ``_PROVIDER_MODELS`` catalog if the API
is unreachable.
r9   rw   )r   listr   provider_model_idsr8   r{   )r   r   livemr   s   &    rX   curated_models_for_providerr(    s}     $H-J\!%&& j)D!%&AB&& !!*b1F#$VGV$$	 ' %s   A1"A6c               $    V ^8  d   QhRRRRRR/# )rS   
model_nameri   r  rT   zOptional[tuple[str, str]]rV   )rW   s   "rX   rY   rY     s+     [ [[[ [rZ   c                b  a T ;'       g    RP                  4       pV'       g   R# VP                  4       o\        P                  SS4      pVR
9  dD   \        P                  V. 4      pV\
        9   d#   V'       d   V\        V4      8w  d   W4^ ,          3# RR0p\        P                  V. 4      p\        ;QJ d    V3R lV 4       F  '       g   K   RM	  RM! V3R lV 4       4      '       d   R# Rp\        P                  4        FW  w  rW8X  g   W9   d   K  \        ;QJ d    V3R lV	 4       F  '       g   K   RM	  RM! V3R lV	 4       4      '       g   KU  Tp M	  V'       d   Rp
 ^ R	I	H
p VP                  V4      pV'       dC   ^ RIpVP                   F.  pVP                  ! VR4      P                  4       '       g   K,  Rp
 M	  V
'       d   Wr3# \        V4      pV'       d   RV3# Wr3# \        V4      pV'       d   VR8w  d   RV3# W8w  d   RV3# R# R#   \         d     L^i ; i)u  Auto-detect the best provider for a model name.

Returns ``(provider_id, model_name)`` — the model name may be remapped
(e.g. bare ``deepseek-chat`` → ``deepseek/deepseek-chat`` for OpenRouter).
Returns ``None`` when no confident match is found.

Priority:
0. Bare provider name → switch to that provider's default model
1. Direct provider with credentials (highest)
2. Direct provider without credentials → remap to OpenRouter slug
3. OpenRouter catalog match
rw   Nr9   r   c              3  J   <"   T F  pSVP                  4       8H  x  K  	  R # 5iNr  r   r'  
name_lowers   & rX   r   ,detect_provider_for_model.<locals>.<genexpr>  s     
;Nq:"N    #TFc              3  J   <"   T F  pSVP                  4       8H  x  K  	  R # 5ir-  r.  r/  s   & rX   r   r1    s     71zQWWY&r2  )PROVIDER_REGISTRY>   r>   r9   )r   r  r   r{   r8   r   r   anyr   r   r4  r   api_key_env_varsr   r   _find_openrouter_slug)r*  r  nameresolved_providerdefault_models_AGGREGATORScurrent_modelsdirect_matchr  r   r  r4  pconfigr   env_varor_slugr0  s   &&              @rX   detect_provider_for_modelrA    s     "##%DJ *--j*E 88)--.?D!11!%78H%II%a'899 L)L &))*:B?N
s
;N
;sss
;N
;;; #'L'--/"c&93773337777L 0 	
	9'++L9G&77Gyy"-3355$(	  8  '' (- '** ## $D)G|+ '**? '**3  		s$   .H  7H  	H  H   H.-H.c                    V ^8  d   QhRRRR/# )rS   r*  ri   rT   r"  rV   )rW   s   "rX   rY   rY     s      c m rZ   c                ,   V P                  4       P                  4       pV'       g   R# \         F  w  r#WP                  4       8X  g   K  Vu # 	  \         F:  w  r#RV9   g   K  VP                  R^4      w  r4WP                  4       8X  g   K8  Vu # 	  R# )u  Find the full OpenRouter model slug for a bare or partial model name.

Handles:
- Exact match: ``anthropic/claude-opus-4.6`` → as-is
- Bare name: ``deepseek-chat`` → ``deepseek/deepseek-chat``
- Bare name: ``claude-opus-4.6`` → ``anthropic/claude-opus-4.6``
Nr   )r   r  r   split)r*  r0  r\   r]   r  s   &    rX   r7  r7    s     !!#))+J $$J $
 $#:IIc1-MA--//
	 $ rZ   c                    V ^8  d   QhRRRR/# rS   r   r"  rT   ri   rV   )rW   s   "rX   rY   rY     s     9 9 93 9rZ   c                |    T ;'       g    RP                  4       P                  4       p\        P                  W4      # )u   Normalize provider aliases to Hermes' canonical provider ids.

Note: ``"auto"`` passes through unchanged — use
``hermes_cli.auth.resolve_provider()`` to resolve it to a concrete
provider based on credentials and environment.
r9   )r   r  r   r{   )r   r   s   & rX   r   r     s4     **l11399;J  88rZ   c                    V ^8  d   QhRRRR/# rF  rV   )rW   s   "rX   rY   rY   (  s     F F] Fs FrZ   c                    T ;'       g    RP                  4       pVP                  4       pVR8X  d   R# \        V4      p\        P	                  Y!;'       g    R4      # )z9Return a human-friendly label for a provider id or alias.r9   autoAutor:   )r   r  r   r   r{   )r   originalr   s   &  rX   provider_labelrM  (  sR    ((L//1H!JV#J/J
,D,DEErZ   c                   V ^8  d   QhRR/# r   rV   )rW   s   "rX   rY   rY   2  s      # rZ   c                      ^ RI Hp  V ! R4      p\        VP                  R4      ;'       g    R4      P	                  4       #   \
         d     R# i ; i)z@Best-effort GitHub token for fetching the Copilot model catalog.)$resolve_api_key_provider_credentialsr   r   rw   )r   rP  ri   r{   r   r   )rP  r   s     rX    _resolve_copilot_catalog_api_keyrQ  2  sK    H4Y?599Y'--2.4466 s   *A A AAc                    V ^8  d   QhRRRR/# )rS   r   r"  rT   rU   rV   )rW   s   "rX   rY   rY   =  s     56 56 569 56rZ   c                   \        V 4      pVR8X  d   \        4       # VR8X  d   ^ RIHp V! 4       # VR9   dF    \	        \        4       4      pV'       d   V#  VR8X  d    \        \        P                  R. 4      4      # VR8X  dM    ^ RI
HpHp V! 4       pV'       d5   V! VP                  RR	4      VP                  R
R	4      R7      pV'       d   V# VR8X  d   \        4       pV'       d   V# VR8X  d   \        4       pV'       d   V# VR8X  d}   \        4       pV'       dk   \         P"                  ! RR	4      ;'       g7    \         P"                  ! RR	4      ;'       g    \         P"                  ! RR	4      p\%        W4      pV'       d   V# \        \        P                  V. 4      4      #   \         d     EL_i ; i  \         d     Li ; i)zReturn the best known model catalog for a provider.

Tries live API endpoints for providers that support them (Codex, Nous),
falling back to static lists.
r9   r   )get_codex_model_idsr   r   r   )fetch_nous_modelsr   r   rw   r   )r   inference_base_urlr(   r1   r>   CUSTOM_API_KEYOPENAI_API_KEYr   >   r   r   )r   r^   hermes_cli.codex_modelsrT  _fetch_github_modelsrQ  r   r$  r8   r{   r   rU  r   _fetch_anthropic_models_fetch_ai_gateway_modelsr  r   r   fetch_api_models)	r   r   rT  r&  rU  r   r   r   r   s	   &        rX   r%  r%  =  s    $H-J\!{^#?"$$//	'(H(JKD  &(,,Y;<<V	[46E(9b1I^c^g^ghrtv^wxK [ &(K\!')KX') 		*B/ 7 799-r27 799126 
 $G6D $$Z455G  		  		s/   F( F: 1F: F: (F76F7:GGc                    V ^8  d   QhRRRR/# rS   r   rn   rT   Optional[list[str]]rV   )rW   s   "rX   rY   rY   u  s     ) )U )5H )rZ   c                <    ^ RI HpHp T! 4       pT'       g   R# RR/pT! T4      '       d,   RT 2TR&   ^ RI HpHp RP                  YV,           4      TR	&   MY4R
&   \        P                  P                  RTR7      p \        P                  P                  YpR7      ;_uu_ 4       p\        P                  ! TP                  4       P                  4       4      p	T	P                  R. 4       U
u. uF$  qP                  R4      '       g   K  T
R,          NK&  	  pp
\!        TR R7      uuRRR4       #   \         d     R# i ; iu up
i   + '       g   i     R# ; i  \"         d5   p^ RIpTP'                  \(        4      P+                  RT4        Rp?R# Rp?ii ; i)zFetch available models from the Anthropic /v1/models endpoint.

Uses resolve_anthropic_token() to find credentials (env vars or
Claude Code auto-discovery).  Returns sorted model IDs or None.
)resolve_anthropic_token_is_oauth_tokenNzanthropic-versionz
2023-06-01r   r   )_COMMON_BETAS_OAUTH_ONLY_BETAS,zanthropic-betaz	x-api-keyz#https://api.anthropic.com/v1/modelsr   r   r   r   c                     R V 9  RV 9  RV 9  V 3# )opussonnethaikurV   )r'  s   &rX   <lambda>)_fetch_anthropic_models.<locals>.<lambda>  s!    a!q 	1rZ   )keyz$Failed to fetch Anthropic models: %s)agent.anthropic_adapterrb  rc  ImportErrorrd  re  r|   r   r   r   r   r   r   r   r   r{   sortedr   logging	getLogger__name__debug)r   rb  rc  tokenr   rd  re  r   r   r   r'  r   erq  s   &             rX   r[  r[  u  s^   T $%E2LAGu%,UG#4 L$'HH]-N$O !$
..
 
 - ! C^^##C#99T::diik0023D'+xx';K';!uuT{gagg';FK& ' 	 :9)  , L :99  (#))*PRSTs`   D1 >(E &AE-E
EE&
E 1E ?E EE	E E F')FFc                    V ^8  d   QhRRRR/# )rS   r   r   rT   zlist[dict[str, Any]]rV   )rW   s   "rX   rY   rY     s      C $8 rZ   c                j   \        V \        4      '       d+   V  Uu. uF  p\        V\        4      '       g   K  VNK  	  up# \        V \        4      '       dS   V P                  R . 4      p\        V\        4      '       d+   V Uu. uF  p\        V\        4      '       g   K  VNK  	  up# . # u upi u upi )r   )r   r$  r   r{   )r   r   r   s   &  rX   _payload_itemsry    s    '4  !(CJtT,BCC'4  {{62&dD!!%)DTTZd-CDDTDDI D Es   B+B+B0 B0c                    V ^8  d   QhRRRR/# )rS   r   r   rT   rU   rV   )rW   s   "rX   rY   rY     s     V V V	 VrZ   c                    \        V 4       Uu. uF-  qP                  R 4      '       g   K  VP                  R R4      NK/  	  up# u upi )r   rw   )ry  r{   )r   r   s   & rX   _extract_model_idsr|    s7    +9'+BU+B4hhtnDHHT2+BUUUs
   AAc                   V ^8  d   QhRR/# )rS   rT   zdict[str, str]rV   )rW   s   "rX   rY   rY     s     
 
 
rZ   c            	     `     ^ RI Hp  V ! RR7      #   \         d    R\        RRRRR	R
/u # i ; i)zStandard headers for Copilot API requests.

Includes Openai-Intent and x-initiator headers that opencode and the
Copilot CLI send on every request.
copilot_request_headersT)is_agent_turnzEditor-Versionz
User-AgentzHermesAgent/1.0zOpenai-Intentzconversation-editszx-initiatoragent)hermes_cli.copilot_authr  ro  COPILOT_EDITOR_VERSIONr  s    rX   copilot_default_headersr    sE    	
C&T:: 
4+17	
 	

s    --c                    V ^8  d   QhRRRR/# )rS   r   dict[str, Any]rT   r   rV   )rW   s   "rX   rY   rY     s      n  rZ   c                   \        V P                  R 4      ;'       g    R4      P                  4       pV'       g   R# V P                  R4      RJ d   R# V P                  R4      p\        V\        4      '       dR   \        VP                  R4      ;'       g    R4      P                  4       P                  4       pV'       d
   VR8w  d   R# V P                  R4      p\        V\        4      '       dm   V Uu0 uF=  p\        V4      P                  4       '       g   K$  \        V4      P                  4       kK?  	  ppV'       d   VP                  0 R	m4      '       g   R# R# u upi )
r   rw   Fmodel_picker_enabledcapabilitiestypechatsupported_endpointsT>   
/responses/v1/messages/chat/completions)ri   r{   r   r   r   r  r$  intersection)r   model_idr  
model_typer  endpointnormalized_endpointss   &      rX   #_copilot_catalog_item_is_text_modelr    s   488D>''R(..0Hxx&'5088N+L,%%))&177R8>>@FFH
*.((#89%t,, 0 
/8}""$ "CM!/ 	  

  (<(I(I?)
 )
  
s   7!E!E!c               $    V ^8  d   QhRRRRRR/# )rS   r   r"  r   rn   rT   Optional[list[dict[str, Any]]]rV   )rW   s   "rX   rY   rY     s$         ,1 # rZ   c           	     d   . pV '       d#   VP                  / \        4       CRRV  2/C4       VP                  \        4       4       V EF;  p\        P                  P	                  \
        VR7      p \        P                  P                  WAR7      ;_uu_ 4       p\        P                  ! VP                  4       P                  4       4      p\        V4      p. p\        4       p	V Fz  p
\        V
4      '       g   K  \        V
P                  R4      ;'       g    R4      P!                  4       pV'       d   W9   d   KX  V	P#                  V4       VP                  V
4       K|  	  V'       d   VuuRRR4       u #  RRR4       EK>  	  R#   + '       g   i     EKT  ; i  \$         d     EKf  i ; i)z=Fetch the live GitHub Copilot model catalog for this account.r   r   r   r   r   rw   N)rb   r  r   r   r   COPILOT_MODELS_URLr   r   r   r   r   ry  setr  ri   r{   r   addr   )r   r   attemptsr   r   r   r   r   r   seen_idsr   r  s   &&          rX   fetch_github_model_catalogr    s`    &(H 
%'
wwi0
 	 OO+-.nn$$%7$I	'''==zz$))+"4"4"67&t,/1%(U!D>tDD "488D>#7#7R8>>@H#x'; LL*MM$' " ! >=  >= ( # >==  		sI   2(FA>F
F
65F
,F
-
F;F
FFFF/.F/c                    V ^8  d   QhRRRR/# )rS   r   r"  rT   r   rV   )rW   s   "rX   rY   rY     s       4 rZ   c                    T ;'       g    R P                  4       P                  R4      P                  4       pVP                  \        4      ;'       g    VP                  R4      # )rw   r   z"https://models.github.ai/inference)r   r   r  
startswithCOPILOT_BASE_URL)r   r   s   & rX   _is_github_models_base_urlr    sY    ..b'')005;;=J./ 	G 	G  !EFrZ   c               $    V ^8  d   QhRRRRRR/# )rS   r   r"  r   rn   rT   r`  rV   )rW   s   "rX   rY   rY   	  s'     F F- F FQd FrZ   c                    \        WR 7      pV'       g   R# V Uu. uF-  q3P                  R4      '       g   K  VP                  RR4      NK/  	  up# u upi )r   r   Nr   rw   )r  r{   )r   r   catalogr   s   &&  rX   rZ  rZ  	  s@    (JG+2E74hhtnDHHT27EEEs
   AAzopenai/gpt-5-chatzopenai/gpt-5-minizopenai/gpt-5-nanozopenai/gpt-4.1-nanozopenai/gpt-4ozopenai/gpt-4o-mini	openai/o1zopenai/o1-minizopenai/o1-preview	openai/o3zopenai/o3-minizopenai/o4-minic               $    V ^8  d   QhRRRRRR/# )rS   r  r  r   r"  rT   r   rV   )rW   s   "rX   rY   rY   '  s&      + rZ   c                X   V f   V'       d   \        VR7      p V '       g   \        4       # V  Uu0 uFo  p\        VP                  R4      ;'       g    R4      P	                  4       '       g   K=  \        VP                  R4      ;'       g    R4      P	                  4       kKq  	  up# u upi )Nr   r   rw   )r  r  ri   r{   r   )r  r   r   s   && rX   _copilot_catalog_idsr  '  s     7,W=u Dtxx~##$**, 	*DHHTN  b!'')  s   !B'B'.B'B'r  r   c               (    V ^8  d   QhRRRRRRRR/# rS   r  r"  r  r  r   rT   ri   rV   )rW   s   "rX   rY   rY   6  s2     & && ,& 	&
 	&rZ   c               D   \        T ;'       g    R 4      P                  4       pV'       g   R # \        WR7      p\        P	                  V4      pV'       d   V# V.pRV9   d7   VP                  VP                  R^4      ^,          P                  4       4       VP                  R4      '       d   VP                  VRR 4       VP                  R4      '       d   VP                  VRR 4       VP                  R4      '       d   VP                  VRR 4       \        4       pV FH  pV'       d   W9   d   K  VP                  V4       V\        9   d   \        V,          u # W9   g   KF  Vu # 	  RV9   d(   VP                  R^4      ^,          P                  4       # V# )rw   r  r   r   z-miniNz-nanoz-chat)
ri   r   r  _COPILOT_MODEL_ALIASESr{   rb   rD  r   r  r  )	r  r  r   r  catalog_idsr  
candidatesseen	candidates	   &$$      rX   normalize_copilot_model_idr  6  sX    hnn"

#
#
%C&wHK"&&s+EJ
cz#))C+A.4467
||G#cr(#
||G#cr(#
||G#cr(#UD	I-..))44#   czyya #))++JrZ   c                    V ^8  d   QhRRRR/# )rS   r  ri   rT   rU   rV   )rW   s   "rX   rY   rY   _  s      S Y rZ   c                    T ;'       g    R P                  4       P                  4       pVP                  R4      '       d   \        \        4      # \        V 4      P                  4       pVP                  R4      '       d   \        \        4      # . # )rw   r-   )r  r  z	openai/o4o1o3o4)r   r  r  r$  "COPILOT_REASONING_EFFORTS_O_SERIESr  COPILOT_REASONING_EFFORTS_GPT5)r  r  r   s   &  rX   &_github_reasoning_efforts_for_model_idr  _  sp    >>r
 
 
"
(
(
*C
~~OPP677+H5;;=JW%%233IrZ   c                    V ^8  d   QhRRRR/# )rS   r  ri   rT   r   rV   )rW   s   "rX   rY   rY   i  s     @ @ @ @rZ   c                    ^ RI pVP                  RV 4      pV'       g   R# \        VP                  ^4      4      pV^8  ;'       d    V P	                  R4      '       * # )a  Decide whether a Copilot model should use the Responses API.

Replicates opencode's ``shouldUseCopilotResponsesApi`` logic:
GPT-5+ models use Responses API, except ``gpt-5-mini`` which uses
Chat Completions.  All non-GPT models (Claude, Gemini, etc.) use
Chat Completions.
Nz
^gpt-(\d+)Fr   )rematchintgroupr  )r  r  r  majors   &   rX   !_should_use_copilot_responses_apir  i  sO     HH]H-EAEA:??h11,???rZ   c               (    V ^8  d   QhRRRRRRRR/# r  rV   )rW   s   "rX   rY   rY   z  s2     $ $$ ,$ 	$
 	$rZ   c                 a \        WVR7      oS'       g   R# \        S4      '       d   R# Vf   V'       d   \        VR7      pV'       d   \        V3R lV 4       R4      p\	        V\
        4      '       ds   VP                  R4      ;'       g    .  Uu0 uF=  p\        V4      P                  4       '       g   K$  \        V4      P                  4       kK?  	  ppRV9   d
   R	V9  d   R
# R# u upi )zDetermine the API mode for a Copilot model.

Uses the model ID pattern (matching opencode's approach) as the
primary signal.  Falls back to the catalog's ``supported_endpoints``
only for models not covered by the pattern check.
r  chat_completionscodex_responsesNr  c              3  V   <"   T F  qP                  R 4      S8X  g   K  Vx  K   	  R# 5ir   Nr{   r   r   r   s   & rX   r   )copilot_model_api_mode.<locals>.<genexpr>        Wwt((4.J:Vddw   )
)r  r  r  anthropic_messages)	r  r  r  nextr   r   r{   ri   r   )r  r  r   catalog_entryr  r  r   s   &$$   @rX   copilot_model_api_moder  z  s     ,HwWJ! )44  7,W=WwWY]^mT** "/!2!23H!I!O!OR!O#!OHx=&&( &H##%!O   # !449LTg9g+#s   !C,;C,c               $    V ^8  d   QhRRRRRR/# rS   provider_idr"  r  rT   ri   rV   )rW   s   "rX   rY   rY     s"     
 
] 
m 
X[ 
rZ   c                    \        V 4      p\        T;'       g    R4      P                  4       pV'       d   VR9  d   V# V R2pVP                  4       P	                  V4      '       d   V\        V4      R # V# )zJNormalize OpenCode config IDs to the bare model slug used in API requests.rw   r   N>   r0   r,   )r   ri   r   r  r  r   )r  r  r   currentprefixs   &&   rX   normalize_opencode_model_idr    sm    !+.H(..b!'')Gh&EEz^F}}!!&))s6{|$$NrZ   c               $    V ^8  d   QhRRRRRR/# r  rV   )rW   s   "rX   rY   rY     s"       - TW rZ   c                   \        V 4      p\        W4      P                  4       pV'       g   R# VR8X  d   VP                  R4      '       d   R# R# VR8X  d5   VP                  R4      '       d   R# VP                  R4      '       d   R# R# R# )	a  Determine the API mode for an OpenCode Zen / Go model.

OpenCode routes different models behind different API surfaces:

- GPT-5 / Codex models on Zen use ``/v1/responses``
- Claude models on Zen use ``/v1/messages``
- MiniMax models on Go use ``/v1/messages``
- GLM / Kimi on Go use ``/v1/chat/completions``
- Other Zen models (Gemini, GLM, Kimi, MiniMax, Qwen, etc.) use
  ``/v1/chat/completions``

This follows the published OpenCode docs for Zen and Go endpoints.
r  r0   zminimax-r  r,   zclaude-zgpt-r  )r   r  r  r  )r  r  r   r   s   &&  rX   opencode_model_api_moder    s|     "+.H,[CIIKJ!=   ,,'!>!  ++'  (($!rZ   c               (    V ^8  d   QhRRRRRRRR/# )rS   r  r"  r  r  r   rT   rU   rV   )rW   s   "rX   rY   rY     s8     )O )O)O ,)O 	)O
 )OrZ   c                 a \        WVR7      oS'       g   . # RpVe   \        V3R lV 4       R4      pM2V'       d+   \        VR7      pV'       d   \        V3R lV 4       R4      pVEe]   VP                  R4      p\	        V\
        4      '       d   VP                  R4      p\	        V\
        4      '       d   VP                  R4      p\	        V\        4      '       dv   V Uu. uFK  p\        V4      P                  4       '       g   K$  \        V4      P                  4       P                  4       NKM  	  p	p\        \
        P                  V	4      4      # . # VP                  R. 4       U
u0 uFK  p
\        V
4      P                  4       '       g   K$  \        V
4      P                  4       P                  4       kKM  	  pp
R	V9  d   . # \        \        T ;'       g    S4      4      # u upi u up
i )
zEReturn supported reasoning-effort levels for a Copilot-visible model.r  Nc              3  V   <"   T F  qP                  R 4      S8X  g   K  Vx  K   	  R# 5ir  r  r  s   & rX   r   1github_model_reasoning_efforts.<locals>.<genexpr>  r  r  r  c              3  V   <"   T F  qP                  R 4      S8X  g   K  Vx  K   	  R# 5ir  r  r  s   & rX   r   r    s!     !c?4hhtnXbFb$$?r  r  supportsreasoning_effort	reasoning)r  r  r  r{   r   r   r$  ri   r   r  fromkeysr  )r  r  r   r  fetched_catalogr  r  effortseffortnormalized_efforts
capabilitylegacy_capabilitiesr   s   &$$         @rX   github_model_reasoning_effortsr    s    ,HwWJ	MWwWY]^	4WE !c?!ceijM $((8lD))#''
3H(D))",,'9:gt,, '.*&-Fv;,,. 4F))+113&- ' *
  .@ ABBI ,//C
C
:$$& ,C
O!!#))+C 	 

 11I1#h6L6L*2MNN*
s   &!G'+G'-!G,+G,c               (    V ^8  d   QhRRRRRRRR/# )rS   r   r"  r   r   rn   rT   r  rV   )rW   s   "rX   rY   rY     s6     A AAA A 	ArZ   c                   T;'       g    RP                  4       P                  R4      pV'       g   RRRRRRRRRR	/# \        V4      '       d!   \        WR
7      pRVR\        R\
        RRRR	/# VP                  R4      '       d   VRR P                  R4      pM	VR,           pVR	3.pV'       d   WS8w  d   VP                  VR34       . p/ pV '       d	   RV  2VR&   VP                  \
        4      '       d   VP                  \        4       4       V EF  w  rV	P                  R4      R,           pVP                  V4       \        P                  P                  WR7      p \        P                  P                  WR7      ;_uu_ 4       p\        P                   ! VP#                  4       P%                  4       4      pRVP'                  R. 4       Uu. uF  qP'                  RR4      NK  	  upRTRV	P                  R4      RWY8w  d   TMTRV
/uuRRR4       u # 	  RRRV'       d
   VR,          MVP                  R4      R,           RTRWS8w  d   VRR	/# RRR	/# u upi   + '       g   i     EK`  ; i  \(         d     EKr  i ; i)zJProbe an OpenAI-compatible ``/models`` endpoint with light URL heuristics.rw   r   r   N
probed_urlresolved_base_urlsuggested_base_urlused_fallbackFr  r   Tr   r   r   r   r   r   r   r   )r   r   r  rZ  r  r  r   rb   r  updater  r   r   r   r   r   r   r   r   r{   r   )r   r   r   r   r   alternate_baser  triedr   candidate_baseis_fallbackr   r   r   r   r'  s   &&&             rX   probe_api_modelsr    s{    ..b'')005Jd$ $U
 	
 "*--%gGf,!1 $U
 	
 5!!#CR//4#e++5u*=)>J.6>401E G%,WI#6 -...01'1###C(94Snn$$S$:	'''==zz$))+"4"4"678LM8L1uuT28LM #')>)>s)C(N<\.bl#[ >= (2$ 	$5eBij.?.?.Dy.PZ0Ln  SW  N >==  		sC   $(I7AI"I."I"
I7I""I4-I74I77JJc                    V ^8  d   QhRRRR/# r_  rV   )rW   s   "rX   rY   rY   @  s      e 6I rZ   c           	     b   \         P                  ! RR4      P                  4       pV'       g   R# \         P                  ! RR4      P                  4       pV'       g	   ^ RIHp TpVP                  R4      R,           pRR	V 2/p\        P                  P                  WER
7      p \        P                  P                  W`R7      ;_uu_ 4       p\        P                  ! VP                  4       P                  4       4      pVP                  R. 4       U	u. uF_  p	V	P                  R4      '       g   K  V	P                  R4      R8X  g   K4  RV	P                  R4      ;'       g    . 9   g   KV  V	R,          NKa  	  up	uuRRR4       # u up	i   + '       g   i     R# ; i  \         d     R# i ; i)z>Fetch available language models with tool-use from AI Gateway.AI_GATEWAY_API_KEYrw   NAI_GATEWAY_BASE_URL)r  r   r   r   r   r   r   r   r   r  languageztool-usetags)r   r   r   hermes_constantsr  r   r   r   r   r   r   r   r   r   r{   r   )
r   r   r   r  r   r   r   r   r   r'  s
   &         rX   r\  r\  @  s[   ii,b1779Gyy.399;H8&
//#

*C.''0CDG
..
 
 
 
6C^^##C#99T::diik0023D &"--A55;  EE&MZ/  155=#6#6B7	 $- :9 :99  s[   %(F AFF2F
F#F,F9F;
F FF	F F F.-F.c               (    V ^8  d   QhRRRRRRRR/# )rS   r   r"  r   r   rn   rT   r`  rV   )rW   s   "rX   rY   rY   [  s6     
N 
N
N
N 
N 	
NrZ   c                :    \        WVR7      P                  R4      # )zFetch the list of available model IDs from the provider's ``/models`` endpoint.

Returns a list of model ID strings, or ``None`` if the endpoint could not
be reached (network error, timeout, auth failure, etc.).
r   r   )r  r{   )r   r   r   s   &&&rX   r]  r]  [  s     Gw?CCHMMrZ   r   c          
     ,    V ^8  d   QhRRRRRRRRRR/# )	rS   r*  ri   r   r"  r   r   rT   r  rV   )rW   s   "rX   rY   rY   h  sA     K KKK 	K
 K KrZ   c                  T ;'       g    RP                  4       p\        V4      pVR8X  d   V'       d
   RV9  d   RpTpVR8X  d   \        VVR7      ;'       g    TpV'       g   RRR	RR
RRR/# \        ;QJ d    R V 4       F  '       g   K   RM	  RM! R V 4       4      '       d   RRR	RR
RRR/# VR8X  Ed   \	        W#4      pVP                  R4      pVe   V\        V4      9   d   RRR	RR
RRR/# \        WH^RR7      p	Rp
V	'       d    RRP                  R V	 4       4      ,           p
RV RVP                  R4       RV
 2pVP                  R4      '       d   VRVP                  R4       R2,          pRRR	RR
RRV/# RVP                  R4       R V R!2pVP                  R"4      '       d   VR#VP                  R"4       R$2,          pRRR	RR
RRV/# \        W#4      pVeb   V\        V4      9   d   RRR	RR
RRR/# \        WH^RR7      p	Rp
V	'       d    RRP                  R% V	 4       4      ,           p
RRR	RR
RRRV R&V
 2/# \        P                  WU4      pRRR	RR
RRR'V R(V R)2/# )*a  
Validate a ``/model`` value for the active provider.

Performs format checks first, then probes the live API to confirm
the model actually exists.

Returns a dict with:
  - accepted: whether the CLI should switch to the requested model now
  - persist: whether it is safe to save to config
  - recognized: whether it matched a known provider catalog
  - message: optional warning / guidance for the user
rw   r9   zopenrouter.air>   r   r  acceptedFpersist
recognizedmessagezModel name cannot be empty.c              3  @   "   T F  qP                  4       x  K  	  R # 5ir-  )isspace)r   chs   & rX   r   +validate_requested_model.<locals>.<genexpr>  s     
,)B::<<)s   Tz"Model names cannot contain spaces.r   Ng      ?)ncutoffz
  Similar models: z, c              3  .   "   T F  pR V R 2x  K  	  R# 5i`NrV   r   ss   & rX   r   r         DcWbRSq1XWb   zNote: `z9` was not found in this custom endpoint's model listing (r  zE). It may still work if the server supports hidden or aliased models.r  z1
  Endpoint verification succeeded after trying `r  z)`. Consider saving that as your base URL.z?Note: could not reach this custom endpoint's model listing at `z`. Hermes will still save `z=`, but the endpoint should expose `/models` for verification.r  z0
  If this server expects `/v1`, try base URL: `r  c              3  .   "   T F  pR V R 2x  K  	  R# 5ir  rV   r  s   & rX   r   r    r  r  z]` was not found in this provider's model listing. It may still work if your plan supports it.zCould not reach the z API to validate `z:`. If the service isn't down, this model may not be valid.)r   r   r  r5  r  r{   r  r   r|   r]  r   )r*  r   r   r   	requestedr   requested_for_lookupprobe
api_modelssuggestionssuggestion_textr  rM  s   &&$$         rX   validate_requested_modelr#  h  sL   & !!r((*I#H-J\!h?(3R
$Y9 
      	
 u%4	
 	
 s
,)
,sss
,)
,,,u%;	
 	
 X 3YYx(
!#s:6t $t	  ,IQsSK O"8499DcWbDc;c"c ) %IIl+,,q"#% 
 yy))HSfIgHh i= > D4e7	  NeiiXdNeMf g''0k1np 	 99)**J599UiKjJkklmmG t%w	
 	
 "'4J3z?2 D4d4	  ,IQsSK O"8499DcWbDc;c"c D4ei[ )B&')	 	 &))*AND4e">"22DYK PF G rZ   )minimallowmediumhigh)r%  r&  r'  ))r   recommended)r   rw   )zqwen/qwen3.6-plus:freerl   )r	   rw   )r
   rw   )openai/gpt-5.4rw   )openai/gpt-5.4-minirw   )xiaomi/mimo-v2-prorw   )openai/gpt-5.3-codexrw   )google/gemini-3-pro-previewrw   )google/gemini-3-flash-previewrw   )google/gemini-3.1-pro-previewrw   )$google/gemini-3.1-flash-lite-previewrw   )qwen/qwen3.5-plus-02-15rw   )qwen/qwen3.5-35b-a3brw   )stepfun/step-3.5-flashrw   )minimax/minimax-m2.7rw   )minimax/minimax-m2.5rw   )
z-ai/glm-5rw   )z-ai/glm-5-turborw   )moonshotai/kimi-k2.5rw   )x-ai/grok-4.20-betarw   )!nvidia/nemotron-3-super-120b-a12brw   )&nvidia/nemotron-3-super-120b-a12b:freerl   )#arcee-ai/trinity-large-preview:freerl   )arcee-ai/trinity-large-thinkingrw   )openai/gpt-5.4-prorw   )openai/gpt-5.4-nanorw   )r   r   r	   r
   r)  r*  r+  r,  r-  r.  r/  r0  r1  r2  r3  r4  r5  r6  r7  r8  r9  r:  r;  r<  r=  r>  r?  )r   r   r   r   )r   zgpt-5.4-minir   r   r   r   r   r   r   r   r   r   gemini-2.5-prozgrok-code-fast-1)zgemini-3.1-pro-previewzgemini-3-flash-previewzgemini-3.1-flash-lite-previewr@  zgemini-2.5-flashzgemini-2.5-flash-litezgemma-4-31b-itzgemma-4-26b-it)r    zglm-5-turbor!   zglm-4.5zglm-4.5-flash)zkimi-for-codingr#   r$   zkimi-k2-thinking-turbokimi-k2-turbo-previewkimi-k2-0905-preview)r#   r$   rA  rB  )zMiniMax-M2.7zMiniMax-M2.7-highspeedMiniMax-M2.5zMiniMax-M2.5-highspeedzMiniMax-M2.1)r)   r*   zclaude-opus-4-5-20251101zclaude-sonnet-4-5-20250929zclaude-opus-4-20250514zclaude-sonnet-4-20250514zclaude-haiku-4-5-20251001)r    r#   zmimo-v2-prozmimo-v2-omnir.   r/   )r   r   r	   r
   r2   r3   r4   r-  zgoogle/gemini-3-flashzgoogle/gemini-2.5-prozgoogle/gemini-2.5-flashzdeepseek/deepseek-v3.2)r   r   r)  r-  r.  )zqwen3.5-pluszqwen3-coder-pluszqwen3-coder-nextr    r!   r#   rC  )zQwen/Qwen3.5-397B-A17BzQwen/Qwen3.5-35B-A3Bzdeepseek-ai/DeepSeek-V3.2zmoonshotai/Kimi-K2.5zMiniMaxAI/MiniMax-M2.5zzai-org/GLM-5zXiaomiMiMo/MiMo-V2-Flashzmoonshotai/Kimi-K2-Thinking)rw   z      )Nr   g       @)      @)NrD  )NN)F__conditional_annotations____doc__
__future__r   r   r   urllib.requestr   urllib.errordifflibr   typingr   r   r  r  r  r  r  GITHUB_MODELS_BASE_URLGITHUB_MODELS_CATALOG_URLr   __annotations__r8   r   r   r^   re   rf   rs   r   r   r   r   r   r   r  keysr   r  r  r  r(  rA  r7  r   rM  rQ  r%  r[  ry  r|  r  r  r  r  rZ  r  r  r  r  r  r  r  r  r  r  r\  r]  r#  )rE  s   @rX   <module>rP     sy   #  	   %  2 ()1 ) !E %> " * . , ( >O*
 O*<  =O*H IO*N  OO*n  
oO*D 
 EO*R  SO*b  cO*n  oO*|  }O*J  KO*\ ]O*d  %%% 	% 		%
 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	%  	!%" 	#%$ 	%%& 	'%( 	)%* 	+%, 	-%. 	/%0 	1%2 	3%4 	5%6 	7%8 	9%: 	;%< 	=%> 	?%@ 	A%B 	C%D 	E%F 	G%H 	I%eO*p  qO*@  AO*\  ]O*t  	uO*J  	KO* & Ob,N ' M	
    
< $ y #  
 N = ,  !" *#$ >' ,'n'	5' E' E	'
 U' i' i' Y' I' -' ' h' X' ' M'  !'" \#'$ ,%'& k''( ;)'* +', -'. 
>/'0 	-1'2 }3'4 5'6 l7'8 9': J;'< ='> J?'@ A'B iC'D IE'F Y-M}M' T1
 8:4 90(2; ;|-
  - -`7
	2  	

 
 
"#$X x +\!(H
%*[|69F56p) )XV
$:   FF FL  	
 i 9 9 X -  l   l l   !2!" "#6#$ "#6 "4' . & /3& "	&R@"$ /3$ "	$N
D)O /3)O "	)OXA AH 6
N 
NK "	K
 #K KrZ   