
    )j+0                      d Z ddlmZ ddlZddlZddlZddlmZmZm	Z	  ej
        e          ZddlmZ ddlmZmZmZmZ ddlmZmZmZmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z% ddl&m'Z'm(Z( dd	l)m*Z* dd
l+m,Z,m-Z-m.Z. dKdZ/dLdZ0dMdZ1dNdZ2dOdZ3dOdZ4dPdZ5dQdRdZ6dSd!Z7h d"Z8dTd%Z9dUd(Z:dddd)dVd0Z;dQdWd2Z<	 	 dXdYd6Z=dZd9Z>d[d:Z?d\d;Z@d]d=ZAddd>d^dAZBddd>d_dBZCddddCd`dDZDddd>dadEZEdddddFdbdGZFdcdJZGdS )dzGShared runtime provider resolution for CLI, gateway, cron, and helpers.    )annotationsN)AnyDictOptional)auth)CredentialPoolPooledCredentialget_custom_provider_pool_key	load_pool)	AuthErrorDEFAULT_CODEX_BASE_URLDEFAULT_QWEN_BASE_URLDEFAULT_XAI_OAUTH_BASE_URLPROVIDER_REGISTRY_agent_key_is_usableformat_auth_errorresolve_provider resolve_nous_runtime_credentials!resolve_codex_runtime_credentials%resolve_xai_oauth_runtime_credentials resolve_qwen_runtime_credentials(resolve_gemini_oauth_runtime_credentials$resolve_api_key_provider_credentials-resolve_external_process_provider_credentialshas_usable_secret)get_compatible_custom_providersload_config)OPENROUTER_BASE_URL)base_url_host_matchesbase_url_hostnameenv_intvaluestrreturnc                v    |                                                                                      dd          S )N -)striplowerreplace)r"   s    @/home/ubuntu/.hermes/hermes-agent/hermes_cli/runtime_provider.py_normalize_custom_provider_namer,   %   s,    ;;==  ((c222    hostboolc                \    | pd                                                     d          }|dv S )N .>   ::10.0.0.0	localhost	127.0.0.1)r)   rstrip)r.   hs     r+   _loopback_hostnamer9   )   s1    	##C((A<<<r-   cfg_base_urlcfg_providerc                D   |pd                                                                 }| pd                                 }|sdS |dk    rdS 	 ddlm}  ||          dk    rdS n# t          $ r Y nw xY wt          |d          rdS t          t          |                    S )u  Decide whether ``model.base_url`` may back bare ``custom`` runtime resolution.

    GitHub #14676: the model picker can select Custom while ``model.provider`` still reflects a
    previous provider. Reject non-loopback URLs unless the YAML provider is already ``custom``
    (or one of the local-server aliases that resolve to ``custom`` — ollama, vllm, llamacpp, …),
    so a stale OpenRouter/Z.ai base_url cannot hijack local ``custom`` sessions.
    r1   FcustomTr   r   openrouter.ai)r(   r)   hermes_cli.authr   	Exceptionr   r9   r    )r:   r;   cfg_provider_normbu_resolve_providers        r+   ,_config_base_url_trustworthy_for_bare_customrE   .   s     &+2244::<<

"	#	#	%	%B uH$$t
IIIIII.//8;;4 <   R11 u/33444s   A$ $
A10A1base_urlOptional[str]c                    | pd                                                                                     d          }t          |           }|dk    rdS |dk    rdS |                    d          rdS |dk    rd	|v rdS d
S )u  Auto-detect api_mode from the resolved base URL.

    - Direct api.openai.com endpoints need the Responses API for GPT-5.x
      tool calls with reasoning (chat/completions returns 400).
    - Third-party Anthropic-compatible gateways (MiniMax, Zhipu GLM,
      LiteLLM proxies, etc.) conventionally expose the native Anthropic
      protocol under a ``/anthropic`` suffix — treat those as
      ``anthropic_messages`` transport instead of the default
      ``chat_completions``.
    - Kimi Code's ``api.kimi.com/coding`` endpoint also speaks the
      Anthropic Messages protocol (the /coding route accepts Claude
      Code's native request shape).
    r1   /zapi.x.aicodex_responseszapi.openai.comz
/anthropicanthropic_messageszapi.kimi.comz/codingN)r(   r)   r7   r    endswith)rF   
normalizedhostnames      r+   _detect_api_mode_for_urlrO   L   s     .b''))//1188==J **H:  ###  <(( $##>!!i:&=&=##4r-   c                |   t          |           }|sdS t          d |                    d          d         D                       rdS |dv sd|v rdS d |                    d          D             }|r+|d         d	v r!|                    d           |r
|d         d	v !t	          |          d
k     rdS |d         }d                    d |D                                                       }|r|d                                         sdS |dv rdS | d}t          j	        |d          pd
                                S )u_  Look up `<VENDOR>_API_KEY` in the env, derived from the base URL host.

    Examples:
        https://api.deepseek.com/v1   → DEEPSEEK_API_KEY
        https://api.groq.com/openai/v1 → GROQ_API_KEY
        https://api.mistral.ai/v1     → MISTRAL_API_KEY
        https://generativelanguage.googleapis.com/v1beta/openai/ → GOOGLEAPIS_API_KEY

    Returns the env value (stripped) or "". Never returns env vars whose names
    are already explicitly checked elsewhere — those are handled by their own
    host-gated paths (OPENAI/OPENROUTER/OLLAMA).

    The vendor label is the *registrable* portion of the hostname: strip
    ``api.`` / ``www.`` prefixes, then take the second-to-last label
    (``api.deepseek.com`` → ``deepseek``). Falls back to "" for hostnames
    that don't yield a usable vendor label (IPs, loopback, single-label
    hosts).
    r1   c              3  >   K   | ]}|                                 V  d S N)isdigit.0chs     r+   	<genexpr>z(_host_derived_api_key.<locals>.<genexpr>~   s*      
:
:B2::<<
:
:
:
:
:
:r-   r2   )r5   :c                    g | ]}||S  r[   )rU   lbls     r+   
<listcomp>z)_host_derived_api_key.<locals>.<listcomp>   s    888cC8c888r-   r   )apiwww   c              3  F   K   | ]}|                                 r|nd V  dS )_N)isalnumrT   s     r+   rW   z(_host_derived_api_key.<locals>.<genexpr>   s3      EEbjjll3EEEEEEr-   )OPENAI
OPENROUTEROLLAMA_API_KEY)r    anysplitpoplenjoinupperisalphaosgetenvr(   )rF   rN   labelsvendor	sanitizedenv_names         r+   _host_derived_api_keyrv   g   sx   & !**H r

:
:(.."5"5b"9
:
:
::: r>!!SH__r88X^^C00888F
 VAY.00

1  VAY.00
6{{Qr BZFEEfEEEEEKKMMI IaL0022 r666r%%%HIh##)r00222r-   c                   | sdS 	 ddl }|                     d          }|                    d          s|dz  }|                    |dz   d          }|j        r[|                                                    d	g           }t          |          d
k    r |d                             dd          }|r|S n3# t          $ r&}t          	                    d| |           Y d}~nd}~ww xY wdS )zFQuery a local server for its model name when only one model is loaded.r1   r   NrI   z/v1z/models   )timeoutdata   idz$Auto-detect model from %s failed: %s)
requestsr7   rL   getokjsonrl   rA   loggerdebug)rF   r}   urlrespmodelsmodel_idexcs          r+   _auto_detect_local_modelr      s    rLooc""||E"" 	5LC||C)OQ|777 	$YY[[__VR00F6{{a!!9==r22 $#O L L L 	;XsKKKKKKKKL 2s   B.B6 6
C& C!!C&Dict[str, Any]c                 r   t                      } |                     d          }t          |t                    rt          |          }|                    d          s |                    d          r|d         |d<   |                    d          pd                                }|                    d          pd                                }d|v pd|v }| }|r|r|rt          |          }|r||d<   |S t          |t                    r*|                                rd|                                iS i S )Nmodeldefaultr1   rF   r5   r6   )r   r~   
isinstancedictr(   r   r#   )config	model_cfgcfgr   rF   is_localis_fallbackdetecteds           r+   _get_model_configr      sB   ]]F

7##I)T"" 9oowwy!! 	*cggg&6&6 	* \C	N779%%+2244GGJ''-24466(*EkX.E!k 	* 	* 	*/99H *!)I
)S!! .ioo&7&7 .9??,,--Ir-   providerconfigured_providerc                    | pd                                                                 }|pd                                                                 }|sdS |dk    r|dk    p|                    d          S ||k    S )aT  Check whether a persisted api_mode should be honored for a given provider.

    Prevents stale api_mode from a previous provider leaking into a
    different one after a model/provider switch.  Only applies the
    persisted mode when the config's provider matches the runtime
    provider (or when no configured provider is recorded).
    r1   Tr=   custom:)r(   r)   
startswith)r   r   normalized_providernormalized_configureds       r+   $_provider_supports_explicit_api_moder      s     $>r002288::06B==??EEGG  th&&$0_4I4T4TU^4_4__ $777r-   r   api_keyc                   t          |                     d          pd                                                                          }t	          |                     d                    }|rt          d|          r|S t          |                     d          pd                                          }|sdS 	 ddlm}  |||	          S # t          $ r Y dS w xY w)
Nr   r1   api_modecopilotr   chat_completionsr   )copilot_model_api_mode)r   )	r#   r~   r(   r)   _parse_api_moder   hermes_cli.modelsr   rA   )r   r   r   configured_mode
model_namer   s         r+   _copilot_runtime_api_moder      s    immJ77=2>>DDFFLLNN%immJ&?&?@@O ?	K^__ Y]]9--344::<<J "!!"<<<<<<%%j'BBBB " " "!!!"s   :C 
CC>   rJ   bedrock_converser   codex_app_serverrK   rawr   c                    t          | t                    r1|                                                                 }|t          v r|S dS )z@Validate an api_mode value from config. Returns None if invalid.N)r   r#   r(   r)   _VALID_API_MODES)r   rM   s     r+   r   r      sD    #s YY[[&&((
)))4r-   r   Optional[Dict[str, Any]]c                    |s|S | dvr|S t          |                    d          pd                                                                          }|dk    rdS |S )u  Optional opt-in: rewrite api_mode → "codex_app_server" for OpenAI/Codex
    providers when the user has explicitly enabled that runtime via
    `model.openai_runtime: codex_app_server` in config.yaml.

    Default behavior is preserved: when the key is unset, "auto", or empty,
    this function is a no-op. Only providers in {"openai", "openai-codex"}
    are eligible — other providers (anthropic, openrouter, etc.) cannot be
    rerouted through codex.

    Returns the (possibly-rewritten) api_mode.>   openaiopenai-codexopenai_runtimer1   r   )r#   r~   r(   r)   )r   r   r   runtimes       r+   %_maybe_apply_codex_app_server_runtimer     sp       111)-- 0117R88>>@@FFHHG$$$!!Or-   )r   pooltarget_modelentryr	   requested_providerr   Optional[CredentialPool]r   c           	     N	   |pt                      }|p|                    d          pd}t          |dd           pt          |dd           pd                    d          }t          |dd           pt          |dd          }d}	| d	k    rd
}	|pt          }n| dk    rd
}	|pt
          }n| dk    rd}	|pt          }n| dk    rd}	|pd}n| dk    r%d}	t          j        |           }
|p
|
r|
j        nd}ne| dk    rd}	t          |                    d          pd          
                                                                }d}|dk    rIt          |                    d          pd          
                                                    d          }|p|pd}n| dk    r|pt          }n| dk    rd
}	n| dk    rd}	n| dk    r5t          |t          |dd                    }	|pt          d         j        }n\| dk    rt          |                    d          pd          
                                                                }|dk    rst          |                    d          pd          
                                                    d          }|r|}t          |                    d                    }|r|}	|r/|	dk    r)	 ddlm}  ||          }n# t"          $ r d }Y nw xY w|r|}	|	dk    rt%          j        dd|          }nEt          |                    d          pd          
                                                                }t          j        |           }
|
o0|                    d          |
j                            d          k    }|| k    rO|rMt          |                    d          pd          
                                                    d          }|r|}t          |                    d                    }| dv rddlm}  || |          }	n(|rt+          | |          r|}	nt-          |          }|r|}	|	dk    r| dv rt%          j        dd|          }t/          | |	|          }	| |	||t          |d d!          ||d"S )#Nr   r1   runtime_base_urlrF   rI   runtime_api_keyaccess_tokenr   r   rJ   	xai-oauth
qwen-oauthgoogle-gemini-clizcloudcode-pa://googleminimax-oauthrK   	anthropicr   https://api.anthropic.com
openrouterxainousr   azure-foundryr   r   azure_foundry_model_api_mode/v1/?$   opencode-goopencode-zenopencode_model_api_mode)r   r   r   sourcer   )r   r   rF   r   r   credential_poolr   )r   r~   getattrr7   r   r   r   r   inference_base_urlr#   r(   r)   r   r   r   r   r   rA   resubr   r   rO   r   )r   r   r   r   r   r   effective_modelrF   r   r   pconfigr;   r:   r   r   inferredr   pool_url_is_defaultr   r   s                       r+    _resolve_runtime_from_pool_entryr   !  sw    0.00I $Ey}}Y'?'?E2O1488bGE:W[<\<\b`bjjknooHe.55[XZ9[9[G!H>!!$55	[	 	 $99	\	!	!%44	(	(	(%66	_	$	$
 (#'11Ng M : :2	[	 	 '9==44:;;AACCIIKK;&&y}}Z88>B??EEGGNNsSSLJ8J/J	\	!	!22	U		$	V		%	Y		,YGXZ\8]8]^^N0;N	_	$	$9==44:;;AACCIIKK?**y}}Z88>B??EEGGNNsSSL ('-immJ.G.GHHO +*
  	$x+??? JJJJJJ77HH        $#+++viX66H!)--
";";"ArBBHHJJPPRR
 $'11%h(//#*>*>'B\BcBcdgBhBh*h(**/B*y}}Z88>B??EEGGNNsSSL ('))--
*C*CDD666 BAAAAA..xIIHH 	$!EhPc!d!d 	$&HH
 099H $# '''H8W,W,W6)R22 5H	  H
 %6220  s   K# #K21K2	requestedc                   | r:|                                  r&|                                                                  S t                      }|                    d          }t	          |t
                    r:|                                 r&|                                                                 S t          j        dd                                                                           }|r|S dS )z=Resolve provider request from explicit arg, config, then env.r   HERMES_INFERENCE_PROVIDERr1   auto)r(   r)   r   r~   r   r#   rp   rq   )r   r   r;   env_providers       r+   resolve_requested_providerr     s     )Y__&& )  &&(((!##I==,,L,$$ ,););)=)= ,!!##))+++ 98"==CCEEKKMML 6r-   provider_labelapi_mode_overrideprovider_namec                P   t          | |          }|sdS 	 t          |          }|                                sdS |                                }|dS t	          |dd          pt	          |dd          }|sdS ||pt          |           pd| |d| |dS # t          $ r Y dS w xY w)	zXCheck if a credential pool exists for a custom endpoint and return a runtime dict if so.r   Nr   r   r1   r   zpool:)r   r   rF   r   r   r   )r
   r   has_credentialsselectr   rO   rA   )rF   r   r   r   pool_keyr   r   pool_api_keys           r+   _try_resolve_from_custom_poolr     s     ,HMRRRH t""##%% 	4=4u&7>>d'%Q_acBdBd 	4&)e-Eh-O-OeSe #(h((#
 
 	
    tts"   #B B $B :B 
B%$B%resultNonec                    dD ]:}|                      |          }t          |t                    r|dk    r||d<    dS ;dS )aq  Propagate a per-provider output cap onto the resolved runtime dict.

    Accepts ``max_output_tokens`` or ``max_tokens`` on a ``custom_providers``
    entry so a provider block can pin its own output limit. Gateway and CLI
    map this onto ``AIAgent.max_tokens`` only when the top-level
    ``model.max_tokens`` isn't set, so the documented global key still wins.
    )max_output_tokens
max_tokensr   r   N)r~   r   int)r   r   _k_vs       r+   _lift_max_output_tokensr     sY     2  YYr]]b# 	266*,F&'FF	 r-   c           	     
   t          | pd          }|sd S |dk    rd S |dk    ri|                    d          sT	 t          j        |          }|pd                                                                |k    rd S n# t          $ r Y nw xY wt                      }|                    d          }t          |t                    r)|                                D ]\  }}t          |t                    st          |          }t          |                    dd          pd                                          }|r't          j        |d                                          nd}	|	s7t          |                    dd          pd                                          }	|||d| hv r|                    d          p+|                    d	          p|                    d
          pd}
|
r|                    d|          |
                                |	|                    dd          d}|                    d          }t          |t                    rt          |          |d<   t          |                    d          p|                    d                    }|r||d<   t!          ||           |c S |                    dd          }|rt          |          }|||d| hv r|                    d          p+|                    d	          p|                    d
          pd}
|
r||
                                |	|                    dd          d}|                    d          }t          |t                    rt          |          |d<   t          |                    d          p|                    d                    }|r||d<   t!          ||           |c S |                    d          }t          |t                    rt"                              d           d S t'          |          }|sd S |D ]7}t          |t                    s|                    d          }|                    d
          }
t          |t                    rt          |
t                    snt          |          }d| }t          |                    dd          pd                                          }|rt          |          nd}|rd| nd}|||||hvr|                                |
                                t          |                    dd          pd                                          d}t          |                    dd          pd                                          }|r||d<   |r||d<   |                    d          }t          |t                    rt          |          |d<   t          |                    d                    }|r||d<   t          |                    dd          pd                                          }|r||d<   t!          ||           |c S d S )Nr1   r   r=   r   	providerskey_envr   r^   r   rF   namedefault_model)r   rF   r   r   
extra_bodyr   	transportcustom_providerszcustom_providers in config.yaml is a dict, not a list. Each entry must be prefixed with '-' in YAML. Run 'hermes doctor' for details.provider_key)r   rF   r   r   )r,   r   auth_modr   r(   r)   r   r   r~   r   r   itemsr#   rp   rq   r   r   r   warningr   )r   requested_norm	canonicalr   r   ep_namer   	name_normr   resolved_api_keyrF   r   r   r   display_namedisplay_normr   r   menu_keyr   provider_key_normprovider_menu_keyr   s                          r+   _get_named_custom_providerr
    s   45G5M2NNN t" t!!.*C*CI*N*N!	 1.AAI R&&((..00NBBt C  	 	 	D	 ]]F 

;''I)T"" ;&'oo// :	& :	&NGUeT** 7@@I%))Ir228b99??AAGAHPry"55;;===b# O#&uyyB'?'?'E2#F#F#L#L#N#N '96K	6K6K!LLL 99U++^uyy/?/?^599ZCXCX^\^ " %		&' : :$,NN$4$4#3!&?B!?!?	 F "'<!8!8J!*d33 @/3J/?/?|,  /uyy/D/D/^		R]H^H^__H 6-5z*+E6:::!MMM 99VR00L &>|LL!lLBZLBZBZ%[[[$yy//b599U3C3CbuyyQ[G\G\b`bH &$0(0(8(8'7%*YY%C%C	" " &+YY|%<%<
%j$77 D37
3C3CF<0#2599Z3H3H3bEIIVaLbLb#c#c# :19F:./v>>>% zz"455"D)) /	
 	
 	

 t6v>> t! " "%&& 	yy  99Z(($$$ 	Jx,E,E 	3D99	(Y((599^R88>B??EEGGMYa;LIII_a=NV9&7999TV)X7HJ[!\\\JJLL ((599Y339r::@@BB
 

 eii	2..4"55;;== 	( 'F9 	2%1F>"YY|,,
j$'' 	4#'
#3#3F< "599Z#8#899 	*!)F:7B//5266<<>>
 	)(F7Ov...4s   A= =
B
	B
c                H    	 t          |           duS # t          $ r Y dS w xY w)u~  Return True when config defines a custom provider matching the request.

    Thin public wrapper around :func:`_get_named_custom_provider` so other
    modules (e.g. the cronjob tool) can decide whether a provider name will
    actually resolve to a configured ``providers:`` / ``custom_providers:``
    entry — without reaching into a private helper or duplicating the scan.
    NF)r
  rA   )r   s    r+   has_named_custom_providerr    s=    )*<==TII   uus    
!!custom_providerc                    |                      d          }t          |t                    r|si S dt          |          iS )Nr   )r~   r   r   )r  r   s     r+   "_custom_provider_request_overridesr    sF     $$\22Jj$'' z 	$z**++r-   explicit_api_keyexplicit_base_urlr  r  c           
     H	   | pd                                                                 }|r/|dk    r)	 ddlm}  ||          dk    rd}n# t          $ r Y nw xY w|dk    r!|r|                                                     d          }t          |dd           }|rd|d<   |S t          |d          pt          |d	          }t          |d
          }|pd                                 |r't          j	        dd                                           nd|r't          j	        dd                                           ndt          |          g}	t          d |	D             d          pd}
dt          |          pd||
d| dS t          |           }|sd S |pd                                 p|                    dd                              d          }|sd S t          |d|                    d          |                    d                    }|r|                    d          }|r||d<   t          |                    d          t                     r|d         |d<   t#          |          }|r+i t%          |                    d          pi           ||d<   |S t          |d          pt          |d	          }t          |d
          }|pd                                 t'          |                    dd          pd                                           t          j	        t'          |                    dd          pd                                           d                                           |r't          j	        dd                                           nd|r't          j	        dd                                           ndt          |          g}	t          d |	D             d          }
d|                    d          pt          |          pd||
pdd|                    d|            d}|                    d          r|d         |d<   t          |                    d          t                     r|d         |d<   t#          |          }|r||d<   |S )Nr1   r=   r   r>   rI   zdirect-aliasr   
openai.comopenai.azure.comr?   OPENAI_API_KEYOPENROUTER_API_KEYc              3  8   K   | ]}t          |          |V  d S rR   r   )rU   cs     r+   rW   z0_resolve_named_custom_runtime.<locals>.<genexpr>  s0      CC1.?.B.BCQCCCCCCr-   no-key-requiredr   r   r   rF   r   r   r   rF   r   r   r   r   r   request_overridesr   r   c              3  8   K   | ]}t          |          |V  d S rR   r  rU   	candidates     r+   rW   z0_resolve_named_custom_runtime.<locals>.<genexpr>  s1      bb)EVW`EaEabIbbbbbbr-   zcustom_provider:r   r   rF   r   r   )r(   r)   r@   r   rA   r7   r   r   rp   rq   rv   nextrO   r
  r~   r   r   r  r   r#   )r   r  r  r   rD   rF   pool_result_da_is_openai_url_da_is_openrouterapi_key_candidatesr   r  r   r  _cp_is_openai_url_cp_is_openrouterr   s                    r+   _resolve_named_custom_runtimer)    s    ).B5577==??N .H44	MMMMMM  00H<<!) 	 	 	D	!!&7!$**,,33C88 4HhMM 	$2K!3HlKK  COdem  pB  PC  PC3HoNN#**,,<MURY',,22444SU<MVRY+R0066888TV "(++	
 CC*CCC
 
   	
 !0::P>P $"4
 
 	
 11CDDO t 
	 b'')) 	/z2..fSkk   t 0(ODWDWXbDcDc  tC  tG  tG  HN  tO  tO  P  P  PK  %((11
 	.#-K o))*=>>DD 	T/>?R/SK+,>OO 	0{':;;ArBB0#0K+, /,GG~K`aik}K~K~//JJ		R&&((O	2..4"55;;==
	#o)))R88>B??EEGGLLRRTT 9J	R#R	(	(	.	.	0	0	0PR8I	R'	,	,	2	2	4	4	4PR 	h'' bb/AbbbdfggG #''
33 #H--//V_%8%8AS%T%TVV F 7## 3)'2w/%%&9::C@@ K&56I&J"#:?KK 8&7"#Ms   A
 

AAc           	        t                      }t          |                    d          t                    r|                    d          nd}t          |                    d          t                    r|                    d          nd}d}dD ]V}|                    |          }t          |t                    r*|                                r|                                } nW| pd                                                                }	|                                                                }|	r/|	dk    r)	 ddlm}
  |
|	          dk    rd}	n# t          $ r Y nw xY wt          j
        dd                                          }t          j
        d	d                                          }d
}|                                r+|s)|	dk    r|r|dk    rd}n|	dk    rt          ||          rd}|pd                                p"|p |r|                                ndp|pt                              d          }t          |d          }|p(|	dk    o"|p||k    o||pd                    d          k    }|r*|t          j
        d          t          j
        d          g}nt          |d          }t          |d          }t          |d          }||r|nd|rt          j
        d          nd|s|rt          j
        d          nd|rt          j
        d          ndt          |          g}t!          d |D             d          }|s|rdnd}|	dk    rdnd}|dk    rA|r?t#          ||t%          |                    d                    |	dk    r| nd           }|r|S |dk    r|s|sd}|t%          |                    d                    pt'          |          pd|||dS )NrF   r1   r   )r   r^   r=   r   r>   r   CUSTOM_BASE_URLFr   TrI   r?   r   r  r  z
ollama.comr  r  OLLAMA_API_KEYc              3  z   K   | ]6}t          |          t          |pd                                           V  7dS )r1   N)r   r#   r(   r  s     r+   rW   z._resolve_openrouter_runtime.<locals>.<genexpr>  sI      jj)M^_hMiMijY_"			#	#	%	%jjjjjjr-   explicitz
env/configr   r   r  r   r!  )r   r   r~   r#   r(   r)   r@   r   rA   rp   rq   rE   r   r7   r   rv   r"  r   r   rO   )r   r  r  r   r:   r;   cfg_api_keykvr   rD   env_openrouter_base_urlenv_custom_base_urluse_config_base_urlrF   _is_openrouter_url_is_openrouter_contextr&  _is_ollama_url_is_openai_url_is_openai_azurer   r   effective_providerr#  s                            r+   _resolve_openrouter_runtimer;    s    "##I0:9==;T;TVY0Z0Zb9==,,,`bL0:9==;T;TVY0Z0Zb9==,,,`bLK  MM!a 	!'')) 	''))KE(.B5577==??N%%''--//L  .H44	MMMMMM  00H<<!) 	 	 	D	 !i(=rBBHHJJ)$5r::@@BB
   '$5 'V## +<6#9#9&*#x'',X,-
 -
' #' 
	 b'')) 		$7?L   R	 #	 fSkk  /xII 0 ,& 	D$K4K(K	D06B>>sCCC 
   
I*++I&''
 2(LII1(LII1(<NOO /7[[R0>\RY'(((Z\1?\CS\RY'(((Z\0B\RY+,,,Z\
 "(++
 jj7Ijjj
 G
 -T0ATZZF &4x%?%?\ X%%(% 4(/)--
:S:S*T*T0>(0J0J,,PT
 
 
  	X%%g%>P%# '#IMM*$=$=>> #H--  s   ?E 
E$#E$)r  r  r   c           	        t          |pd                                          }t          |pd                                                              d          }t          |                    d          pd                                                                          }d}d}d}	i }
|dk    rt          |                    d          pd                                                              d          }t          |                    d                    pd}t          |                    d	          pd                                                                          pd}	|                    d
          }t          |t                    r|}
t          |p|                    d          pd                                          }|r/|dk    r)	 ddlm	}  ||          }n# t          $ r d}Y nw xY w|r|}t          j        dd                                                              d          }|p|p|}|st          d          |dk    rt          j        dd|          }|	dk    r|r|}d}d}n	 ddlm}m}m} n&# t          $ r}t          d| d          |d}~ww xY wt          |
                    d          pd                                          p|}	  ||          } ||          }n/# t(          $ r"}t          t          |                    |d}~ww xY w|}d}d}i }|dk    r=t          |
                    d          pd                                          }|r||d<   d||||||| dS |}|s'	 ddlm}  |d          pd}n# t          $ r d}Y nw xY w|s't          j        dd                                          }|st          d          |s|rdnd}d|||d|| d S )!a  Resolve an Azure Foundry runtime entry.

    Reads ``model.base_url`` + ``model.api_mode`` from config.yaml (or
    explicit overrides), pulls the API key from ``.env`` / env var, and
    strips a trailing ``/v1`` for Anthropic-style endpoints because the
    Anthropic SDK appends ``/v1/messages`` internally.

    When ``model.auth_mode == "entra_id"`` (and the model is OpenAI-style),
    the returned ``api_key`` is a zero-arg callable produced by
    :func:`agent.azure_identity_adapter.build_token_provider` rather than
    a string. Downstream code that constructs an OpenAI SDK client passes
    this through unchanged (the SDK accepts ``Callable[[], str]`` for
    ``api_key`` and calls it before every request). Code paths that need
    a string (logging, manual HTTP probes, header injection) must use the
    helpers in ``agent.azure_identity_adapter``.

    Raises :class:`AuthError` when required values are missing.
    r1   rI   r   r   r   r   rF   r   	auth_modeentrar   rK   r   r   NAZURE_FOUNDRY_BASE_URLzpAzure Foundry requires a base URL. Set it via 'hermes model' or the AZURE_FOUNDRY_BASE_URL environment variable.r   entra_idr.  )EntraIdentityConfigSCOPE_AI_AZURE_DEFAULTbuild_token_providerzAzure Foundry Entra ID auth requires the 'azure-identity' package. Install it with: pip install azure-identity (import failed: )scope)rE  )r   )r   r   rF   r   r=  r>  r   r   )get_env_valueAZURE_FOUNDRY_API_KEYa  Azure Foundry requires an API key. Set AZURE_FOUNDRY_API_KEY in ~/.hermes/.env or run 'hermes model' to configure. To use keyless Microsoft Entra ID auth instead, set model.auth_mode: entra_id in config.yaml (or pick 'Microsoft Entra ID' in 'hermes model').r   )r   r   rF   r   r=  r   r   )r#   r(   r7   r~   r)   r   r   r   r   r   rA   rp   rq   r   r   r   agent.azure_identity_adapterrA  rB  rC  ImportErrorhermes_cli.configrF  )r   r   r  r  r   explicit_base_url_cleanr;   r:   cfg_api_modecfg_auth_mode	cfg_entra_entrar   r   r   env_base_urlrF   r   r   r=  rA  rB  rC  r   rE  entra_configtoken_providerclean_entraconfigured_scoperF  s                                 r+   _resolve_azure_foundry_runtimerU    s6   4 +1r2288::!"3"9r::@@BBII#NNy}}Z006B77==??EEGGLL%LM "I&&9==44:;;AACCJJ3OO&y}}Z'@'@AAWEWIMM+66C)DDJJLLRRTTaXaw''fd## 	I ,H)--	*B*BHbIIOOQQO $<+???	FFFFFF33ODDHH 	 	 	HHH	 	$#L95r::@@BBII#NNL&F,F,H 
?
 
 	
 +++6)R22  
"" !	# ,GF!II          
    .'*. . .  	 IMM'**0b117799 *) 322      "6!5\!J!J!J 3 3 3C))s23$GF"I
"""9==#9#9#?R@@FFHH 8'7G$ ($ " "4	
 	
 		
 G 	777777#m$;<<BGG 	 	 	GGG	 A)3R88>>@@ 
7
 
 	
 -P0APZZF# 0  sT   G& &G54G5:
J 
J(J##J($K= =
L)L$$L)N N*)N*c           
     	   t          |pd                                          }t          |pd                                                              d          }|s|sd S | dk    rt          |                    d          pd                                                                          }d}|dk    rIt          |                    d          pd                                                              d          }|p|pd}|}|s!ddlm}	  |	            }|st          d	          dd
||d|dS | dk    r|pt          }|}d }
|sft                      }|                    dd          }|                    d          }
|s+|                    dd                              d          p|}dd||d|
|dS | dk    rt          j        d          pi }|pRt          |                    d          pt          j                                                                      d          }|pct          |t          dt          dd                              r6t          |                    d          pd                                          nd}|                    d          p|                    d          }|st!          t#          t%          j        dd                              }|                    dd          }|                    d          }|s+|                    dd                              d          p|}dd||d||dS | dk    rt)          ||||           S t+          j        |           }|rj|j        dk    r^d}|j        r?t%          j        |j        d                                                              d          }|}|sF| d!v r9t1          |           }|                    dd                              d          }n	|p|j        }|}|sPt1          |           }|                    dd          }|s)|                    dd                              d          }d}| d"k    rt5          ||          }nC| d#k    rd}n:t7          |                    d$                    }|r|}nt9          |          }|r|}| ||                    d          |d|dS d S )%Nr1   rI   r   r   rF   r   r   resolve_anthropic_tokenNo Anthropic credentials found. Set ANTHROPIC_TOKEN or ANTHROPIC_API_KEY, run 'claude setup-token', or authenticate with 'claude /login'.rK   r.  r  r   r   last_refreshrJ   r   r   rF   r   r   rZ  r   r   r   <   HERMES_NOUS_MIN_KEY_TTL_SECONDS  	agent_keyagent_key_expires_at
expires_atHERMES_NOUS_TIMEOUT_SECONDS15timeout_secondsr   r   r   rF   r   r   ra  r   r   )r   r   r  r  >   kimi-codingkimi-coding-cnr   r   r   )r#   r(   r7   r~   r)   agent.anthropic_adapterrX  r   r   r   r   get_provider_auth_stateDEFAULT_NOUS_INFERENCE_URLr   maxr!   r   floatrp   rq   rU  r   	auth_typebase_url_env_varr   r   r   r   rO   )r   r   r   r  r  r;   r:   rF   r   rX  rZ  credsstatera  r   env_urlr   r   r   s                      r+   _resolve_explicit_runtimers  N  s    +1r2288::-344::<<CCCHH $5 t;9==44:;;AACCIIKK;&&y}}Z88>B??EEGGNNsSSL$SS8S" 	GGGGGG--//G V  
 $,  "4
 
 	
 >!!$>(>" 	M577Eii	2..G 99^44L$ M 99Z44;;C@@LH&)  ("4
 
 	
 6088>B o599122Yh6YZZ``bbiijmnn 	 # 
#B A4HHII C		+&&,"--33555
  	 YY566Q%))L:Q:Q
 	M4 %bi0Mt&T&T U U  E ii	2..G<00J$ M 99Z44;;C@@LH*  $"4
 
 	
 ?""-1-/	
 
 
 	
  #H--G +
7$	11# 	Ri 8"==CCEELLSQQG$ 	A<<<<XFF 99Z44;;C@@"@g&@" 	A8BBEii	2..G A 99Z44;;C@@%y  0GDDHH(HH-immJ.G.GHHO (* 4H== ('H !  ,, "4
 
 	
 4r-   )r   r  r  r   c                   t          |           }|pd                                }|dk    rd|v r|pd                                pMt          j        dd                                          p&t          j        dd                                          }dd|                    d          |d|d	S |d
k    r"t          |t                      |||          }|S t          |||          }|r||d<   |S t          |||          }	t                      }
t          |	||
||          }|r|S |	dk    }|	dk    rt          |
                    d          pd                                                                          }t          |
                    d          pd                                          }t          j        dd                                          }t          j        dd                                          }t          |p|p|          }|r|dv rd}t          |p|          }|dv o| o| }	 |rt          |	          nd}n# t          $ r d}Y nw xY w|r|                                r|                                }d}|"t%          |dd          pt%          |dd          }|	dk    r||r}t'          dt)          dd                    }t%          |dd          t%          |d d          t%          |d!d          d"}t+          ||          st,                              d#           d}||rt1          |	|||
||$          S |	dk    r	 t3          t5          t          j        d%d&                    '          }dd(|                    dd                              d          |                    d)d          |                    d*d+          |                    d,          |d-S # t6          $ r$ |d.k    r t,                              d/           Y nw xY w|	d0k    r	 t;                      }d0d1|                    dd                              d          |                    d)d          |                    d*d2          |                    d3          |d4S # t6          $ r$ |d.k    r t,                              d5           Y nw xY w|	d6k    r	 t=                      }d6d1|                    d          pd                    d          pt>          |                    d)d          |                    d*d2          |                    d3          |d4S # t6          $ r$ |d.k    r t,                              d7           Y nw xY w|	d8k    r	 tA                      }d8d(|                    dd                              d          |                    d)d          |                    d*d9          |                    d:          |d;S # t6          $ r$ |d.k    r t,                              d<           Y nw xY w|	d=k    rZtC          j        |	          }|rD|j"        d>k    r9d?d@l#m$}  |            }|	d|d         |d)         |                    d*dA          |d	S |	dBk    r	 tK                      }dBd(|                    dd          |                    d)d          |                    d*dC          |                    d:          |                    dDd          |                    dEd          |dF	S # t6          $ r$ |d.k    r t,                              dG           Y nw xY w|	dHk    rtM          |	          }dHd(|                    dd                              d          |                    d)d          |                    dId          tO          |                    dJ          pg           |                    d*dK          |dLS |	dk    rt          |
                    d          pd                                                                          }d}|dk    r<|
                    d          pd                                                    d          }|pdM}d|                                v p|od|                                v }|rd}dND ]e}t          |
                    |          pd                                          }|r+t          j        |d                                          }|r nf|s6t          |
                    d)          pd                                          }|sNt          j        dd                                          p&t          j        dd                                          }|st7          dO          n!d?dPl(m)}   |             }|st7          dQ          dd||dR|d	S |	dSk    rd?dTl*m+}!m,}"m-}#m.}$ |dUv }%|%s |!            st7          dVdWX          t_                                          dSi           }&|&                    dY          pd                                p	 |#            }' |"            pdZ}(|&                    d[i           })d}*|)                    d\          rf|)                    d]          rQ|)d\         |)d]         d^}*|)                    d_          r|)d_         |*d`<   |)                    da          r|)da         |*da<   t          |
                    db          pd                                          }+ |$|+          rdSddc|' ddde|(|'d|df},ndSdgdc|' ddde|(|'|dh},|*r|*|,di<   |,S tC          j        |	          }|r|j"        d)k    rta          |	          }t          |
                    d          pd                                                                          }d}||	k    r<|
                    d          pd                                                    d          }|p(|                    dd                              d          }d(}-|	djk    r%tc          |
|                    d)d                    }-n|	dkk    rd1}-nt          |
                    d          pd                                                                          }.te          |
                    dl                    }/|	dmv r+d?dnl3m4}0 |p|
                    dbd          }1 |0|	|1          }-n(|/rtk          |	|.          r|/}-ntm          |          }2|2r|2}-|-dk    r|	dmv rto          j8        dod|          }|	|-||                    d)d          |                    d*dR          |d	S ts          |||          },||,d<   |,S )pa)  Resolve runtime provider credentials for agent execution.

    target_model: Optional override for model_cfg.get("default") when
    computing provider-specific api_mode (e.g. OpenCode Zen/Go where different
    models route through different API surfaces). Callers performing an
    explicit mid-session model switch should pass the new model here so
    api_mode is derived from the model they are switching TO, not the stale
    persisted default. Other callers can leave it None to preserve existing
    behavior (api_mode derived from config).
    r1   r   z	azure.comAZURE_ANTHROPIC_KEYANTHROPIC_API_KEYrK   rI   zazure-explicitr  r   )r   r   r  r  r   )r   r  r  r   r  )r   r   r   r  r  r   r   rF   OPENAI_BASE_URLr   >   r   r=   T>   r   r   Nr   r   r   r\  r]  r^  r_  r`  rE  )r_  r`  rE  zPNous pool entry agent_key expired/missing, falling through to runtime resolution)r   r   r   r   r   r   rb  rc  rd  r   r   r   portalra  rf  r   zUAuto-detected Nous provider but credentials failed; falling through to next provider.r   rJ   zhermes-auth-storerZ  r[  zVAuto-detected Codex provider but credentials failed; falling through to next provider.r   zZAuto-detected xAI OAuth provider but credentials failed; falling through to next provider.r   zqwen-cliexpires_at_ms)r   r   rF   r   r   ry  r   z@Qwen OAuth credentials failed; falling through to next provider.r   oauth_minimaxr   ))resolve_minimax_oauth_runtime_credentialsoauthr   zgoogle-oauthemail
project_id)	r   r   rF   r   r   ry  r}  r~  r   zIGoogle Gemini OAuth credentials failed; falling through to next provider.zcopilot-acpcommandargsprocess)r   r   rF   r   r  r  r   r   r   )r   api_key_envzNo Azure Anthropic API key found. Set AZURE_ANTHROPIC_KEY or ANTHROPIC_API_KEY, or point key_env/api_key_env in your config.yaml model section at a custom env var.rW  rY  envbedrock)has_aws_credentialsresolve_aws_auth_env_varresolve_bedrock_regionis_anthropic_bedrock_model>   aws-bedrockamazon-bedrockawsamazonr  zNo AWS credentials found for Bedrock. Configure one of:
  - AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY
  - AWS_PROFILE (for SSO / named profiles)
  - IAM instance role (EC2, ECS, Lambda)
Or run 'aws configure' to set up credentials.no_aws_credentials)coderegionzaws-sdk-default-chain	guardrailguardrail_identifierguardrail_version)guardrailIdentifierguardrailVersionstream_processing_modestreamProcessingModetracer   zhttps://bedrock-runtime.z.amazonaws.comzaws-sdk)r   r   rF   r   r   r  bedrock_anthropicr   r   )r   r   rF   r   r   r  r   guardrail_configr   r   r   r   r   r   ):r   r(   rp   rq   r7   rU  r   r)  r   rs  r#   r~   r)   r/   r   rA   r   r   r   rl  r!   r   r   r   r   r   rm  r   infor   r   r   r   r   rn  r@   r{  r   r   listri  rX  agent.bedrock_adapterr  r  r  r  r   r   r   r   r   r   r   rO   r   r   r;  )3r   r  r  r   r   	_eff_base
_azure_keyazure_runtimecustom_runtimer   r   explicit_runtimeshould_use_poolr;   r:   env_openai_base_urlr2  has_custom_endpointhas_runtime_overrider   r   r   min_ttl
nous_staterp  r   r{  rF   _is_azure_endpointtokenhint_keyenv_varrX  r  r  r  r  is_explicit_bedrock_cfgr  auth_source_grr  _current_modelr   r   r   r   r   
_effectiver   s3                                                      r+   resolve_runtime_providerr    s   " 4I>> #(b//11I[(([I-E-E#**,, :y.3399;;:y,b117799 	 $,!((--!&"4
 
 	
 _,,61'))-/%
 
 
 2-)+  N
  /A+,)+  H
 "##I0-)+     ,.O<9==44:;;AACCIIKK9==44:;;AACC i(92>>DDFF"$),A2"F"F"L"L"N"N" '"'&
 

  	'L,>>>"&#$4$I8IJJ"88 )'')(( 	&5?y"""4     $$&&  0$77 65."55  v%"3"3"g&GNNOOG$UK>>(/7Mt(T(T 66 J
 (
G<< "oppp!3!#5#)    6	=4 %bi0Mt&T&T U U  E #.!IIj"55<<SAA 99Y33))Hh77#ii55&8    	= 	= 	=!V++ KK < = = = = =	= >!!	=577E*-!IIj"55<<SAA 99Y33))H.ABB %		. 9 9&8    	= 	= 	=!V++ KK < = = = = =	= ;	=9;;E'-"YYz228b@@EEcIc 99Y33))H.ABB %		. 9 9&8    	= 	= 	=!V++KK < = = = = =	= <	=466E(.!IIj"55<<SAA 99Y33))Hj99!&?!;!;&8    	= 	= 	=!V++KK < = = = = =	= ?""#'11 
	w(O;;QQQQQQ==??E$0!*- +))Hg66&8   &&&	=<>>E/.!IIj"55 99Y33))Hn==!&?!;!;7B//#iib99&8
 
 
  	= 	= 	=!V++KK < = = = = =	= =  =hGG%*		*b1188==yyB//yyB//6**0b11ii)44"4	
 	
 		
 ; 9==44:;;AACCIIKK;&&%MM*55;BBDDKKCPPL>#> )HNN,<,<< 
@[L,>,>,@,@@ 	  %	 E6  immH55;<<BBDD Igr2288::E   DIMM)44:;;AACC I3R88>>@@ By!4b99??AA   E   HGGGGG++--E V  
 $, "4
 
 	
 9	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 ),ii 	#6#6#8#8 	@
 *    #}}((B77""8,,299;;W?U?U?W?W..00K4K{B//77)** 	9sww7J/K/K 	9'*+A'B$'(;$<    ww/00 Y;>?W;X !78www 9,/L ) Y]]955;<<BBDD%%n55 	 &0MvMMM$% %)&8	 	GG &.MvMMM$% &8 G  	;*:G&'  #H--G 3
7$	114X>>
 9==44:;;AACCIIKK8##%MM*55;BBDDKKCPPLH599Z#<#<#C#CC#H#H%y  0EIIiQS<T<TUUHH(HH"%immJ&?&?&E2"F"F"L"L"N"N"T"T"V"V-immJ.G.GHHO::: FEEEEE)IY]]9b-I-I
228ZHH  (%I(Tg%h%h (*
 4H== ('H+++<[0[0[viX66H   yyB//ii%00"4
 
 	
 *-)+  G
 %7G !Nsq   ;I IIBO4 4+P"!P",A9R& &+SSBU   +VVA9X +Y ?Y *B\; ;+])(])errorrA   c                h    t          | t                    rt          |           S t          |           S rR   )r   r   r   r#   )r  s    r+   format_runtime_provider_errorr    s.    %## ( '''u::r-   )r"   r#   r$   r#   )r.   r#   r$   r/   )r:   r#   r;   r#   r$   r/   )rF   r#   r$   rG   )rF   r#   r$   r#   )r$   r   rR   )r   rG   r   rG   r$   r/   )r   r   r   r#   r$   r#   )r   r   r$   rG   )r   r#   r   r#   r   r   r$   r#   )r   r#   r   r	   r   r#   r   r   r   r   r   rG   r$   r   )r   rG   r$   r#   )NN)
rF   r#   r   r#   r   rG   r   rG   r$   r   )r   r   r   r   r$   r   )r   r#   r$   r   )r   r#   r$   r/   )r  r   r$   r   )r   r#   r  rG   r  rG   r$   r   )r   r#   r  rG   r  rG   r$   r   )r   r#   r   r   r  rG   r  rG   r   rG   r$   r   )r   r#   r   r#   r   r   r  rG   r  rG   r$   r   )
r   rG   r  rG   r  rG   r   rG   r$   r   )r  rA   r$   r#   )H__doc__
__future__r   loggingrp   r   typingr   r   r   	getLogger__name__r   
hermes_clir   r   agent.credential_poolr   r	   r
   r   r@   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rJ  r   r   hermes_constantsr   utilsr   r    r!   r,   r9   rE   rO   rv   r   r   r   r   r   r   r   r   r   r   r   r
  r  r  r)  r;  rU  rs  r  r  r[   r-   r+   <module>r     sY   M M " " " " " "  				 				 & & & & & & & & & &		8	$	$ ' ' ' ' ' ' k k k k k k k k k k k k                                   $ K J J J J J J J 0 0 0 0 0 0 C C C C C C C C C C3 3 3 3= = = =
5 5 5 5<   663 63 63 63r   .   ,8 8 8 8 8"" " " "$         > +/%)"&F F F F F FR    , (,#'	    @   Z Z Z Zz   , , , , '+'+	x x x x x x| '+'+	I I I I I I` '+'+"&f f f f f f\ '+'+U U U U U Ut  $&*'+"&L L L L L L^     r-   