
    .cj                   z   d Z ddlmZ ddlZddlZddlZddlm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mZ ddl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.m/Z/ ddl0m1Z1 ddl2m3Z3m4Z4m5Z5 d[d\dZ6d]dZ7d^dZ8d_dZ9d`dZ:dad Z;dbd!Z<dcd"Z=dbd#Z>ddd$Z?dedfd'Z@dd(dgd+ZAh d,ZBdhd/ZCdid0ZDdjd3ZEdddd4dkd:ZFdedld<ZG	 	 dmdnd@ZHdodCZIdodDZJdpdEZKdqdFZLd`dGZMdddHdrdJZNdidKZOdsdMZPdddNdtdQZQdddNdudRZRddddSdvdTZSddddSdwdUZTdddddVdxdWZUdydZZVdS )zzGShared runtime provider resolution for CLI, gateway, cron, and helpers.    )annotationsN)urlparse)AnyDictOptional)auth)CredentialPoolPooledCredential credential_pool_matches_providerget_custom_provider_pool_key	load_pool)
get_secret)	AuthErrorDEFAULT_CODEX_BASE_URLDEFAULT_QWEN_BASE_URLDEFAULT_XAI_OAUTH_BASE_URLPROVIDER_REGISTRY_agent_key_is_usable_nous_inference_env_overrideformat_auth_errorresolve_provider resolve_nous_runtime_credentials!resolve_codex_runtime_credentials%resolve_xai_oauth_runtime_credentials resolve_qwen_runtime_credentials$resolve_api_key_provider_credentials-resolve_external_process_provider_credentialshas_usable_secret)get_compatible_custom_providersload_confignormalize_extra_headers)OPENROUTER_BASE_URL)base_url_host_matchesbase_url_hostnameenv_int namestrdefaultreturnc                .    t          | |          }||n|S )a  Profile-scoped replacement for ``os.getenv`` on credential/provider reads.

    Routes through the secret scope (Workstream A): identical to ``os.getenv``
    when multiplexing is off, scope-aware (and fail-closed on an unscoped read)
    when on. Genuinely-global vars are handled inside ``get_secret`` and still
    read ``os.environ``. Keeps the ``(name, default) -> str`` contract every
    call site here already relies on.
    )_get_secret)r'   r)   vals      =/home/ice/.hermes/hermes-agent/hermes_cli/runtime_provider.py_getenvr/   1   s!     dG
$
$C/33w.    valuec                v    |                                                                                      dd          S )N -)striplowerreplacer1   s    r.   _normalize_custom_provider_namer9   >   s,    ;;==  ((c222r0   hostboolc                \    | pd                                                     d          }|dv S )Nr&   .>   ::10.0.0.0	localhost	127.0.0.1)r6   rstrip)r:   hs     r.   _loopback_hostnamerD   B   s1    	##C((A<<<r0   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.
    r&   FcustomTr   r   openrouter.ai)r5   r6   hermes_cli.authr   	Exceptionr#   rD   r$   )rE   rF   cfg_provider_normbu_resolve_providers        r.   ,_config_base_url_trustworthy_for_bare_customrP   G   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k    rdS t	          |          j                            d          }|                    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).
    - Direct api.anthropic.com endpoints must use the native Messages
      API (``/v1/messages``).  Anthropic also exposes an OpenAI-compat
      ``/chat/completions`` shim on the same host, but Pro/Max OAuth
      subscriptions are only billed against the native Messages route;
      hitting the shim accounts against a separate "extra usage" pool
      that is empty by default and surfaces as HTTP 400 "You're out of
      extra usage."  See issue #32243.
    - 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).
    r&   /zapi.x.aicodex_responseszapi.openai.comapi.anthropic.comanthropic_messagesz
/anthropicz/anthropic/v1zapi.kimi.comz/codingN)r5   r6   rB   r$   r   pathendswith)rQ   
normalizedhostnamerX   s       r.   _detect_api_mode_for_urlr\   e   s    * .b''))//1188==J **H:  ###  
 &&&##J$++C00D}}\"" $dmmO&D&D $##>!!i:&=&=##4r0   	model_cfgDict[str, Any]c                    t          |                     d                    }t          |          }|dk    r%|dk    rt                              d|pd           d}|p|pdS )a  Resolve api_mode for legacy/plain ``provider: custom`` endpoints.

    Custom endpoints should stay conservative by default. Only direct OpenAI/xAI
    URLs imply Responses API automatically; named custom providers can opt in via
    their own ``api_mode`` field. This also prevents a stale persisted
    ``model.api_mode: codex_responses`` from forcing generic relays onto the
    Responses path after upgrades or /reset.
    api_moderU   zMIgnoring persisted custom api_mode=codex_responses for non-OpenAI endpoint %sz	(unknown)Nchat_completions)_parse_api_modegetr\   loggerinfo)r]   rQ   configured_modedetected_modes       r.   _resolve_plain_custom_api_moderh      sz     &immJ&?&?@@O,X66M+++AR0R0R[#	
 	
 	
 AmA/AAr0   c                r   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          |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).
    r&   c              3  >   K   | ]}|                                 V  d S N)isdigit.0chs     r.   	<genexpr>z(_host_derived_api_key.<locals>.<genexpr>   s*      
:
:B2::<<
:
:
:
:
:
:r0   r=   )r@   :c                    g | ]}||S  rt   )rn   lbls     r.   
<listcomp>z)_host_derived_api_key.<locals>.<listcomp>   s    888cC8c888r0   r   )apiwww   c              3  F   K   | ]}|                                 r|nd V  dS )_N)isalnumrm   s     r.   rp   z(_host_derived_api_key.<locals>.<genexpr>   s3      EEbjjll3EEEEEEr0   )OPENAI
OPENROUTEROLLAMA_API_KEY)
r$   anysplitpoplenjoinupperisalphar/   r5   )rQ   r[   labelsvendor	sanitizedenv_names         r.   _host_derived_api_keyr      sv   & !**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Hb!!'R..000r0   c                D   | pd                                 }|sdS t          |          pd                                }|sdS |dk    s*|                    d          s|                    d          rdS |                    d          rdS t	          |          dk    rdS dS )	u  Decide whether a configured ``model.base_url`` may back native Anthropic.

    Native ``provider: anthropic`` resolution honors ``model.base_url`` so users
    can point at Anthropic-compatible endpoints (official Anthropic/Claude hosts,
    Azure Foundry, MiniMax/Zhipu/LiteLLM-style ``/anthropic`` proxies, Kimi's
    ``/coding`` route). But a config can carry a *stale* non-Anthropic URL — e.g.
    ``provider: anthropic`` left with ``base_url: https://openrouter.ai/api/v1``
    after a provider switch — which would route Anthropic OAuth/setup-token
    traffic to an OpenAI-compatible aggregator and 404. Ignore those.

    Returns True only when the URL plausibly speaks the Anthropic Messages
    protocol; otherwise the caller falls back to ``https://api.anthropic.com``.
    r&   FrV   z.anthropic.comz.claude.comTz
.azure.comrW   )r5   r$   r6   rY   r\   )rQ   	candidater[   s      r.   _anthropic_base_url_override_okr      s     R&&((I u!),,299;;H u &&&(*;*;<L*M*M&QYQbQbcpQqQq&t&& t  	**.BBBt5r0   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.r&   r   NrT   z/v1z/models   )timeoutdata   idz$Auto-detect model from %s failed: %s)
requestsrB   rY   rc   okjsonr   rL   rd   debug)rQ   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&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modelr)   r&   rQ   r@   rA   )r    rc   
isinstancedictr5   r   r(   )configr]   cfgr)   rQ   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??,,--Ir0   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).
    r&   TrH   custom:)r5   r6   
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7r0   target_modelapi_keyr   c                  t          |                     d          pd                                                                          }t	          |                     d                    }|rt          d|          r|S t          |p|                     d          pd                                          }|sdS 	 ddlm}  |||	          S # t          $ r Y dS w xY w)
Nr   r&   r`   copilotr)   ra   r   )copilot_model_api_mode)r   )	r(   rc   r5   r6   rb   r   hermes_cli.modelsr   rL   )r]   r   r   r   rf   
model_namer   s          r.   _copilot_runtime_api_moder   @  s    immJ77=2>>DDFFLLNN%immJ&?&?@@O ?	K^__  \CY]]9%=%=CDDJJLLJ "!!"<<<<<<%%j'BBBB " " "!!!"s   <C 
CC>   rU   bedrock_conversera   codex_app_serverrW   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(   r5   r6   _VALID_API_MODES)r   rZ   s     r.   rb   rb   k  sD    #s YY[[&&((
)))4r0   c                 "    t                      pdS )uV  Return the trusted Nous runtime base URL override, if configured.

    Delegates to ``auth._nous_inference_env_override`` so every
    ``NOUS_INFERENCE_BASE_URL`` read shares one normalization path
    (trailing-slash stripping, blank → empty). The env source is trusted
    and intentionally bypasses the network host allowlist there.
    r&   )r   rt   r0   r.   !_nous_inference_base_url_overrider   t  s     ())/R/r0   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_runtimer&   r   )r(   rc   r5   r6   )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$$$!!Or0   )r]   poolr   entryr
   requested_providerr   Optional[CredentialPool]c           	     	   |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}	t          j        |           }
|p
|
r|
j        nd}n| dk    rd}	t          |                    d          pd          
                                                                }d}|dk    rZt          |                    d          pd          
                                                    d          }t          |          sd}|p|pd}n| dk    r|pt          }n| dk    rd
}	n| dk    rd}	t                      p|}n| dk    r7t          |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t1          |          }|r|}	| dv rddlm}  || |	|          }t5          | |	|          }	| d k    rt7          j        |          }| |	||t          |d!d"          ||d#S )$Nr)   r&   runtime_base_urlrQ   rT   runtime_api_keyaccess_tokenra   r   rU   	xai-oauth
qwen-oauthminimax-oauthrW   	anthropicr   https://api.anthropic.com
openrouterxainousr   r   azure-foundryr`   r   azure_foundry_model_api_mode/v1/?$   opencode-goopencode-zenopencode_model_api_modenormalize_opencode_base_url)r   r`   r]   lmstudiosourcer   )r   r`   rQ   r   r   credential_poolr   )r   rc   getattrrB   r   r   r   r   inference_base_urlr(   r5   r6   r   r"   r   r   rb   r   r   rL   resubr   r   r\   r   r   auth_mod$_normalize_lmstudio_runtime_base_url)r   r   r   r]   r   r   effective_modelrQ   r   r`   pconfigrF   rE   rf   r   inferredr   pool_url_is_defaultr   r   r   s                        r.    _resolve_runtime_from_pool_entryr     s    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	_	$	$
 (#'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2<@@ "!J8J/J	\	!	!22	U		$	V		%466B(	Y		,E,b11(
 
 

 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 $# 222AAAAAA..x8LL 5H	  H :@JJ %6220  s   &K8 8LL	requestedc                   | r:|                                  r&|                                                                  S t                      }|                    d          }t	          |t
                    r:|                                 r&|                                                                 S t          dd                                                                           }|r|S dS )z=Resolve provider request from explicit arg, config, then env.r   HERMES_INFERENCE_PROVIDERr&   auto)r5   r6   r   rc   r   r(   r/   )r   r]   rF   env_providers       r.   resolve_requested_providerr   ,  s     )Y__&& )  &&(((!##I==,,L,$$ ,););)=)= ,!!##))+++ 6;;AACCIIKKL 6r0   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   r&   ra   zpool:)r   r`   rQ   r   r   r   )r   r   has_credentialsselectr   r\   rL   )rQ   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)rc   r   int)r   r  _k_vs       r.   _lift_max_output_tokensr  _  sY     2  YYr]]b# 	266*,F&'FF	 r0   c                \    t          |                     d                    }|r||d<   dS dS )zCopy a validated ``extra_headers`` dict from a provider entry.

    SECURITY: header values routinely carry credentials (Cloudflare Access
    service tokens, proxy auth, custom bearer schemes). Never log them.
    extra_headersN)r!   rc   )r   r  r  s      r.   _lift_extra_headersr  n  s?     ,EIIo,F,FGGM 0"/0 0r0   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                    rWddlm} |                                D ];\  }}t          |t                    s ||          s(t          |          }t          |                    dd          pd                                          }	|	r"t          |	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!          ||           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!          ||           t#          |                    d          p|                    d                    }|r||d<   t%          ||           |c S =|                    d          }t          |t                    rt&                              d           d S t+          |          }|sd S |D ]G}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!          ||           t#          |                    d                    }|r||d<   t          |                    dd          pd                                          }|r||d<   t%          ||           |c S d S )Nr&   r   rH   r   	providersr   )is_provider_enabledkey_envr   rw   r   rQ   r'   default_model)r'   rQ   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'   rQ   r   r   )r9   r   r   r   r5   r6   r   r    rc   r   r   hermes_cli.configr  itemsr(   r/   r  rb   r  rd   warningr   )r   requested_norm	canonicalr   r  r  ep_namer   	name_normr  resolved_api_keyrQ   r  r  r`   display_namedisplay_normr  r'   menu_keyr  provider_key_normprovider_menu_keyr   s                           r.   _get_named_custom_providerr%  y  s?   45G5M2NNN t" t!!.*C*CI*N*N!	 1.AAI R&&((..00NBBt C  	 	 	D	 ]]F 

;''I)T"" D&999999'oo// B	& B	&NGUeT** 
 '&u-- 7@@I%))Ir228b99??AAG?FNww3399;;;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/?/?|,'v666  /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+E6:::#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< E6***"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%  rL   )r   s    r.   has_named_custom_providerr'     s=    )*<==TII   uus    
!!c                ~   t          |           }|sdS 	 t                      }n# t          $ r Y dS w xY w|                    d          }t	          |t
                    r|                                D ]\  }}t	          |t
                    s|                    d          p+|                    d          p|                    d          pd}t          |          |k    r!dt          t          |                     c S 	 t          |          }n# t          $ r d}Y nw xY w|pg D ]}t	          |t
                    s|                    d          }t	          |t                    r|
                                sWt          |                    d                    |k    rdt          |           c S dS )	uD  Map an endpoint URL back to its canonical ``custom:<name>`` menu key.

    Returns the ``custom:<normalized-name>`` slug of the first ``providers:``
    / ``custom_providers:`` entry whose base_url matches, or ``None`` when no
    entry owns the URL.

    Session persistence stores the agent's *resolved* provider, and for every
    named custom endpoint that is the literal string ``"custom"`` — the entry
    name is lost, and the api_key is deliberately never persisted. The
    endpoint URL is the one durable fact that survives the round-trip, so
    this reverse lookup lets persist/rebuild paths recover the entry identity
    (and with it key_env/api_key/api_mode resolution via
    :func:`_get_named_custom_provider`) instead of failing with
    ``auth_unavailable`` or silently rebuilding with placeholder credentials.
    Nr  rw   r   rQ   r&   r   r'   )_normalize_base_url_for_matchr    rL   rc   r   r   r  r9   r(   r   r5   )	rQ   targetr   r  r  r   	entry_urlr  r'   s	            r.   find_custom_provider_identityr,  .  s
     +844F t   tt 

;''I)T"" Q'oo// 	Q 	QNGUeT** 		%  SEIIe$4$4S		*8M8MSQS  -Y776AAP!@W!N!NPPPPP B :6BB       !'R E E%&& 	yy  $$$ 	DJJLL 	(:)>)>??6IID<TBBDDDDD J 4s   $ 
22D D$#D$)rQ   config_providerr-  c                6   | rt          |           }|r|S t          |pd                                          }|sV	 t          t                                          d          pd                                          }n# t
          $ r d}Y nw xY w|s2t          j                            dd                                          }t          |          }|r|dv rdS 	 t          |          |
                    d          r|S d| S n# t
          $ r Y nw xY wdS )u  Recover a routable ``custom:<name>`` identity for a bare custom provider.

    The bare string ``"custom"`` is the *resolved billing class* shared by
    every named ``providers:`` / ``custom_providers:`` entry — it is NOT a
    routable provider identity (``resolve_runtime_provider("custom")`` falls
    through to the OpenRouter default URL with no api_key, which surfaces to
    the user as "No LLM provider configured").

    Any code path that persists or restores a session's provider override
    must run the resolved provider through this helper so a bare ``"custom"``
    is upgraded back to its durable ``custom:<name>`` menu key. Two recovery
    sources, in priority order:

    1. ``base_url`` — reverse-lookup the entry that owns the endpoint URL
       (the one fact that always survives the persistence round-trip when a
       URL was recorded).
    2. ``config_provider`` — the active ``config.model.provider`` (or its
       ``provider``/``HERMES_INFERENCE_PROVIDER`` equivalent). When the agent
       was built without a base_url on the override (the recurring
       Desktop/TUI regression vector), the configured provider is the only
       durable identity left, so fall back to it when it names a real entry.

    Returns ``custom:<name>`` when a routable identity is recovered, else
    ``None`` (caller keeps whatever it had — bare ``"custom"`` only as a last
    resort, e.g. a genuine ad-hoc endpoint with no config entry).
    r&   r   r   >   r   rH   r   Nr   )r,  r(   r5   r   rc   rL   osenvironr9   r%  r   )rQ   r-  identityr   candidate_norms        r.   canonical_custom_identityr3  a  sf   @  0:: 	O O)r**0022I 	-//33J??E2FFLLNNII 	 	 	III	 LJNN#>CCIIKK	4Y??N ^/OOOt%i00<((33 &%%-^--- =    4s*   AA? ?BB%D	 D	 	
DDc                    t          | pd                                                              d                                          S )Nr&   rT   )r(   r5   rB   r6   r8   s    r.   r)  r)    s:    u{!!##**3//55777r0   custom_providerc                    |                      d          }t          |t                    r|si S dt          |          iS )Nr  )rc   r   r   )r5  r  s     r.   "_custom_provider_request_overridesr7    sF     $$\22Jj$'' z 	$z**++r0   explicit_api_keyexplicit_base_urlr9  r:  c           
     	   | 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          dd                                           nd|r"t          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<   |                    d          rt#          |d                   |d<   |S t          |d          pt          |d	          }t          |d
          }|pd                                 t%          |                    dd          pd                                           t          t%          |                    dd          pd                                           d                                           |r"t          dd                                           nd|r"t          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<   |                    d          rt#          |d                   |d<   t!          |          }|r||d<   |S )Nr&   rH   r   rI   rT   zdirect-aliasr   
openai.comopenai.azure.comrJ   OPENAI_API_KEYOPENROUTER_API_KEYc              3  8   K   | ]}t          |          |V  d S rk   r   )rn   cs     r.   rp   z0_resolve_named_custom_runtime.<locals>.<genexpr>  s0      CC1.?.B.BCQCCCCCCr0   no-key-requiredra   r   r`   rQ   r   r   r   rQ   r`   r'   r   r   r  request_overridesr  r   r  c              3  8   K   | ]}t          |          |V  d S rk   rA  rn   r   s     r.   rp   z0_resolve_named_custom_runtime.<locals>.<genexpr>  s1      bb)EVW`EaEabIbbbbbbr0   zcustom_provider:r   r`   rQ   r   r   )r5   r6   rK   r   rL   rB   r  r#   r/   r   nextr\   r%  rc   r   r  r7  r   r(   )r   r9  r:  r  rO   rQ   pool_result_da_is_openai_url_da_is_openrouterapi_key_candidatesr   r5  r   rE  _cp_is_openai_url_cp_is_openrouterr  s                    r.   _resolve_named_custom_runtimerP    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#**,,:KSW%r**00222QS:KTW)2..44666RT "(++	
 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+, // 	R+/0P+Q+QK(/,GG~K`aik}K~K~//JJ		R&&((O	2..4"55;;==O''	266<"==CCEErJJPPRR 7H	P!2	&	&	,	,	.	.	.b6G	P%r	*	*	0	0	2	2	2b 	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"# ?++ I"&'G"H"H:?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          dd                                          }t          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          d          t          d          g}n~t          |d          }t          |d          }t          |d          }||r|nd|rt          d          nd|s|rt          d          nd|rt          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}||dk    rt%          ||          n2t#          |                    d                    pt'          |          pd|||dS )NrQ   r&   r   )r   rw   rH   r   rI   r"   CUSTOM_BASE_URLFr   TrT   rJ   r   r?  r>  z
ollama.comr<  r=  OLLAMA_API_KEYc              3  z   K   | ]6}t          |          t          |pd                                           V  7dS )r&   N)r   r(   r5   rG  s     r.   rp   z._resolve_openrouter_runtime.<locals>.<genexpr>  sI      jj)M^_hMiMijY_"			#	#	%	%jjjjjjr0   explicitz
env/configr`   r   rC  ra   rH  )r   r   rc   r(   r5   r6   rK   r   rL   r/   rP   r"   rB   r#   r   rI  r  rb   rh   r\   )r   r9  r:  r]   rE   rF   cfg_api_keykvr  rO   env_openrouter_base_urlenv_custom_base_urluse_config_base_urlrQ   _is_openrouter_url_is_openrouter_contextrM  _is_ollama_url_is_openai_url_is_openai_azurer   r   effective_providerrJ  s                            r.   _resolve_openrouter_runtimerb  /  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	 &&;R@@FFHH!"3R88>>@@
   '$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 
   
())$%%
 2(LII1(LII1(<NOO /7[[R.<ZW%&&&XZ/=ZAQZW%&&&XZ.@ZW)***XZ
 "(++
 jj7Ijjj
 G
 -T0ATZZF &4x%?%?\ X%%(% 4(/)--
:S:S*T*T0>(0J0J,,PT
 
 
  	X%%g%>P%# ')) 39hGGGY]]:6677 #H--
 
 
s   ?E 
E$#E$)r9  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          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          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.
    r&   rT   r   ra   r   r   rQ   r`   	auth_modeentrar)   rW   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_idrU  )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)rl  )r   )r   r`   rQ   r   rd  re  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`   rQ   r   rd  r   r   )r(   r5   rB   rc   r6   rb   r   r   r   r   rL   r/   r   r   r   agent.azure_identity_adapterrh  ri  rj  ImportErrorr  rm  )r   r]   r9  r:  r   explicit_base_url_cleanrF   rE   cfg_api_modecfg_auth_mode	cfg_entra_entrar   r   r   env_base_urlrQ   r   r   rd  rh  ri  rj  r   rl  entra_configtoken_providerclean_entraconfigured_scoperm  s                                 r.   _resolve_azure_foundry_runtimer{    s1   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3R88>>@@GGLLL&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	 ?1266<<>> 
7
 
 	
 -P0APZZF# 0  sT   G& &G54G55
J   
J#
JJ#K8 8
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    rZt          |                    d          pd                                                              d          }t          |          s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 }|p`t                      pRt          |                    d          pt          j                                                                      d          }|pct          |t!          dt#          dd                              r6t          |                    d          pd                                          nd}	|                    d          p|                    d          }|	st%          t'          t)          dd                              }|                    dd          }	|                    d          }|s+|                    dd                              d          p|}dd||	d||dS | dk    rt+          ||||           S t-          j        |           }|rg|j        dk    r[d}|j        r:t)          |j        d                                                              d          }|}|sF| d!v r9t3          |           }|                    dd                              d          }n	|p|j        }|}	|	sPt3          |           }|                    dd          }	|s)|                    dd                              d          }d}| d"k    rt7          ||	|#          }nC| d$k    rd}n:t9          |                    d%                    }|r|}nt;          |          }|r|}| ||                    d          |	d|dS d S )&Nr&   rT   r   r   rQ   r   r   resolve_anthropic_tokenNo Anthropic credentials found. Set ANTHROPIC_TOKEN or ANTHROPIC_API_KEY, run 'claude setup-token', or authenticate with 'claude /login'.rW   rU  rD  r   r   last_refreshrU   r   r`   rQ   r   r   r  r   r   r   <   HERMES_NOUS_MIN_KEY_TTL_SECONDS  	agent_keyagent_key_expires_at
expires_atHERMES_NOUS_TIMEOUT_SECONDS15timeout_secondsra   r   r`   rQ   r   r   r  r   r   )r   r]   r9  r:  >   kimi-codingkimi-coding-cnr   r   r   r`   )r(   r5   rB   rc   r6   r   agent.anthropic_adapterr~  r   r   r   r   get_provider_auth_stater   DEFAULT_NOUS_INFERENCE_URLr   maxr%   r   floatr/   r{  r   	auth_typebase_url_env_varr   r   r   rb   r\   )r   r   r]   r9  r:  r   rF   rE   rQ   r   r~  r  credsstater  r   env_urlr`   rf   r   s                       r.   _resolve_explicit_runtimer  f  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2<@@ "!$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022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 %g.KT&R&R S S  E ii	2..G<00J$ M 99Z44;;C@@LH*  $"4
 
 	
 ?""-1-/	
 
 
 	
  #H--G /
7$	11# 	Pg6;;AACCJJ3OOG$ 	A<<<<XFF 99Z44;;C@@"@g&@" 	A8BBEii	2..G A 99Z44;;C@@%y  0)  HH
 (HH-immJ.G.GHHO (* 4H== ('H !  ,, "4
 
 	
 4r0   )r   r9  r:  r   c           
        ? t          |           }ddlm}m}  |            }t	          |t
                    r|                    d          nd}t	          |t
                    rK|                    |          }	t	          |	t
                    r! ||	          st          d|d| d          |dk    r	dd	d
dd|dS |pd                                }
|dk    rzd|
v rv|pd                                pCt          dd                                          p!t          dd                                          }dd|

                    d          |d|dS |dk    r"t          |t                      |||          }|S |dv rBddlm}  |            \  }}|r|st          d          dd	|
                    d          |d|dS t!          |||          }|r||d<   |S |s|st                      }t#          |                    d          pd                                                                          }t#          |                    d          pd                                          ??r:|d v r6d!}t'          ?fd"|D                       st)          |||          }||d<   |S t+          |||#          }t                      }t-          ||||||$          }|r|S |d%k    }|d%k    rt#          |                    d          pd                                                                          }t#          |                    d          pd                                          ?t          d&d                                          }t          d'd                                          }t/          |p|p|          }?r|d(v rd)}t/          |p|          }|d*v o| o| }	 |rt1          |          nd}n# t2          $ r d}Y nw xY w|r|                                r|                                }d}|"t9          |d+d          pt9          |d,d          }|d-k    rO|Lt;          d.t=          d/d0                    }t9          |d1d          t9          |d2d          t9          |d3d          d4} t?          | |          st@          !                    d5           	 |"                                }!n4# t2          $ r'}"t@          !                    d6|"           d}!Y d}"~"nd}"~"ww xY w|!W|!}t9          |d+d          pt9          |d,d          }t9          |d1d          t9          |d2d          t9          |d3d          d4} |rt?          | |          st@          !                    d7           d}|K|rItG          ||t9          |d8d          pt9          |dd          pd9          rtI          ||||||:          S |d-k    r	 tK          tM          t          d;d<                    =          }#d-d	|#                    dd          
                    d          |#                    d>d          |#                    d?d@          |#                    dA          |dBS # t          $ r$ |dCk    r t@          '                    dD           Y nw xY w|dEk    r	 tQ                      }#dEdF|#                    dd          
                    d          |#                    d>d          |#                    d?dG          |#                    dH          |dIS # t          $ r$ |dCk    r t@          '                    dJ           Y nw xY w|dKk    r	 tS                      }#dKdF|#                    d          pd
                    d          ptT          |#                    d>d          |#                    d?dG          |#                    dH          |dIS # t          $ r$ |dCk    r t@          '                    dL           Y nw xY w|dMk    r	 tW                      }#dMd	|#                    dd          
                    d          |#                    d>d          |#                    d?dN          |#                    dO          |dPS # t          $ r$ |dCk    r t@          '                    dQ           Y nw xY w|dRk    rZtY          j        |          }$|$rD|$j-        dSk    r9ddTl.m/}%  |%            }#|d|#d         |#d>         |#                    d?dU          |dS |dVk    rta          |          }#dVd	|#                    dd          
                    d          |#                    d>d          |#                    dWd          tc          |#                    dX          pg           |#                    d?dY          |dZS |dk    rt#          |                    d          pd                                                                          }d?|dk    rM|                    d          pd                                
                    d          ?te          ?          sd??pd[}d|                                v p?od?                                v }&|&rd}d\D ]`}'t#          |                    |'          pd                                          }(|(r&t          |(d                                          }|r na|s6t#          |                    d>          pd                                          }|sDt          dd                                          p!t          dd                                          }|st          d]          n!dd^l3m4})  |)            }|st          d_          dd||d`|dS |dak    rddbl5m6}*m7}+m8},m9}- |dcv }.|.s |*            st          dddef           |                                dai           }/|/                    dg          pd                                p	 |,            }0 |+            pdh}1|/                    dii           }2d}3|2                    dj          rf|2                    dk          rQ|2dj         |2dk         dl}3|2                    dm          r|2dm         |3dn<   |2                    do          r|2do         |3do<   t#          |p|                    dp          pd                                          }4t/          tt          j;                            dqd                                                    }5 |-|4          r|5sdaddr|0 dsdt|1|0d)|du}ndadvdr|0 dsdt|1|0|dw}|3r|3|dx<   |S tY          j        |          }$|$r|$j-        d>k    rty          |          }#t{          |#                    d>                    s<dy>                    |$j?                  }6|6rdz|6 d{nd}7t          d|| d}|7 |d~          t#          |                    d          pd                                                                          }d?||k    r<|                    d          pd                                
                    d          ??p(|#                    dd          
                    d          }d	}8|dk    r't          ||#                    d>d          |          }8n|dk    rdF}8nt#          |                    d          pd                                                                          }9t          |                    d                    }:|dv r+ddlBmC}; |p|                    dpd          }< |;||<          }8n(|:rt          ||9          r|:}8nt          |          }=|=r|=}8|dv rddlBmF}>  |>||8|          }|dk    rt          jH        |          }||8||#                    d>d          |#                    d?d`          |dS t)          |||          }||d<   |S )a)  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).
    r   )r  r    r  Nz	provider z" is disabled in config (providers.z.enabled: false)moara   zmoa://localzmoa-virtual-providerrD  r&   r   z	azure.comAZURE_ANTHROPIC_KEYANTHROPIC_API_KEYrW   rT   zazure-explicitr   )r   r]   r9  r:  r   )vertexzgoogle-vertexz	vertex-aiz
gcp-vertexvertexai)get_vertex_configa  Vertex AI credentials could not be resolved. Vertex uses OAuth2 (not a static API key): provide a service-account JSON via GOOGLE_APPLICATION_CREDENTIALS (or VERTEX_CREDENTIALS_PATH) in ~/.hermes/.env, or run 'gcloud auth application-default login' for ADC. Set the GCP project/region under vertex: in config.yaml if they aren't embedded in the credentials. Run `hermes setup` to install Vertex support.r  zvertex-oauth)r   r9  r:  r   r   rQ   )r   r&   )rJ   zanthropic.comr<  c              3  8   K   | ]}t          |          V  d S rk   )r#   )rn   r:   rE   s     r.   rp   z+resolve_runtime_provider.<locals>.<genexpr>  sA         &lD99     r0   r8  )r   r   r]   r9  r:  r   r   OPENAI_BASE_URLr"   >   r   rH   T>   r   r   r   r   r   r  r  r  r  r  rl  )r  r  rl  zINous pool entry agent_key expired/missing, refreshing selected pool entryz"Nous pool entry refresh failed: %szRNous pool entry agent_key still unavailable, falling through to runtime resolutionr   )rQ   )r   r   r   r]   r   r   r  r  r  r   r   portalr  r  r   zUAuto-detected Nous provider but credentials failed; falling through to next provider.r   rU   zhermes-auth-storer  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`   rQ   r   r   r  r   z@Qwen OAuth credentials failed; falling through to next provider.r   oauth_minimax))resolve_minimax_oauth_runtime_credentialsoauthzcopilot-acpcommandargsprocess)r   r`   rQ   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.r}  r  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)   AWS_BEARER_TOKEN_BEDROCKzhttps://bedrock-runtime.z.amazonaws.comzaws-sdk)r   r`   rQ   r   r   r  bedrock_anthropicr   r   )r   r`   rQ   r   r   r  r   guardrail_configz, z Set r=   z*No usable credentials found for provider 'z'.missing_api_key)r   r  r   r   r   r`   r   r   r   r   )Ir   r  r  r    r   r   rc   
ValueErrorr5   r/   rB   r{  r   agent.vertex_adapterr  r   rP  r(   r6   r   rb  r   r  r;   r   rL   r   r   r   r  r%   r   rd   r   try_refresh_currentr   r   r   r  re   r   r   r   r   r   r  rK   r  r   listr   r  r~  agent.bedrock_adapterr  r  r  r  r/  r0  r   r   r   api_key_env_varsr   rb   r   r   r   r\   r   r   r   )@r   r9  r:  r   r   r  r    	_full_cfg
_provs_cfg_block	_eff_base
_azure_keyazure_runtimer  tokenrQ   custom_runtimer]   rF   _known_cloud_hostsr   r   explicit_runtimeshould_use_poolenv_openai_base_urlrY  has_custom_endpointhas_runtime_overrider   r   r  min_ttl
nous_state	refreshedr   r  r   r  _is_azure_endpointhint_keyenv_varr~  r  r  r  r  is_explicit_bedrock_cfgr  auth_source_grr  _current_model_has_bearer_token	env_nameshintr`   r   rf   r   
_effectiver   r   rE   s@                                                                  @r.   resolve_runtime_providerr    s   " 4I>> CBBBBBBBI/9)T/J/JT{+++PTJ*d##  233fd## 	,?,?,G,G 	C. C C0C C C  
 U""*%-,"4
 
 	
 #(b//11I[(([I-E-E#**,, 8,b1177998*B//5577 	 $,!((--!&"4
 
 	
 _,,61'))-/%
 
 
  ___::::::++--x 		H 		@   !* ,,$"4
 
 	
 3-)+  N
  /A+,  %5 %''	9==44:;;AACCIIKK9==44:;;AACC 	LL88"
     .     
 6'9%5&7  
 1C,-)+  H
 "##I0-)+!     ,.O<9==44:;;AACCIIKK9==44:;;AACC%&7<<BBDD")*?"D"D"J"J"L"L" '"'&
 

  	'L,>>>"&#$4$I8IJJ"88 )'')(( 	&5?y"""4    >$$&& >0$77 65."55  v%"3"g&GNNOOG$UK>>(/7Mt(T(T 66 J
 (
G<< &hiii% $ 8 8 : :II  % % %LL!EsKKK $IIIIII% (%E'8$?? >"5."== !
 &-UK%F%F07?UW[0\0\!(!>!>" "J
 $ &+?
G+T+T &LL!uvvv#%L 0E#5t<< uj$77    4!#5#)    6	=4 %g.KT&R&R S S  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   =  =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2<@@ "!>#> )HNN,<,<< 
@[L,>,>,@,@@ 	  %	 E6  immH55;<<BBDD #GR006688E   DIMM)44:;;AACC 1266<<>> @2B77==??   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 ) \KY]]9-E-EKLLRRTT 0JB!O!O!U!U!W!WXX%%n55 	>O 	 &0MvMMM$% %)&8	 	GG &.MvMMM$% &8 G  	;*:G&'  #H--G H
7$	114X>> !9!5!566 			'":;;I+4<'9''''"DOXOOOO!&    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		)R(()  HH
 (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666EEEEEE228XxPPHz!!DXNNH   yyB//ii%00"4
 
 	
 *-)+  G
 %7G !Nsv   'O; ;P
	P
%S: :
T+T&&T+	BZ   +[[A9] +^ ?^ 
B` +`:9`:A9b> >+c,+c,errorrL   c                h    t          | t                    rt          |           S t          |           S rk   )r   r   r   r(   )r  s    r.   format_runtime_provider_errorr  c  s.    %## ( '''u::r0   )r&   )r'   r(   r)   r(   r*   r(   )r1   r(   r*   r(   )r:   r(   r*   r;   )rE   r(   rF   r(   r*   r;   )rQ   r(   r*   rR   )r]   r^   rQ   r(   r*   r(   )rQ   r(   r*   r(   )rQ   r(   r*   r;   )r*   r^   rk   )r   rR   r   rR   r*   r;   )r]   r^   r   r(   r   rR   r*   r(   )r   r   r*   rR   )r*   r(   )r   r(   r`   r(   r]   r   r*   r(   )r   r(   r   r
   r   r(   r]   r   r   r   r   rR   r*   r^   )r   rR   r*   r(   )NN)
rQ   r(   r   r(   r   rR   r   rR   r*   r   )r   r^   r  r^   r*   r  )r   r(   r*   r   )r   r(   r*   r;   )rQ   rR   r-  rR   r*   rR   )r5  r^   r*   r^   )r   r(   r9  rR   r:  rR   r*   r   )r   r(   r9  rR   r:  rR   r*   r^   )r   r(   r]   r^   r9  rR   r:  rR   r   rR   r*   r^   )r   r(   r   r(   r]   r^   r9  rR   r:  rR   r   rR   r*   r   )
r   rR   r9  rR   r:  rR   r   rR   r*   r^   )r  rL   r*   r(   )W__doc__
__future__r   loggingr/  r   urllib.parser   typingr   r   r   	getLogger__name__rd   
hermes_clir   r   agent.credential_poolr	   r
   r   r   r   agent.secret_scoper   r,   rK   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r   r    r!   hermes_constantsr"   utilsr#   r$   r%   r/   r9   rD   rP   r\   rh   r   r   r   r   r   r   r   rb   r   r   r   r   r  r  r  r%  r'  r,  r3  r)  r7  rP  rb  r{  r  r  r  rt   r0   r.   <module>r     s   M M " " " " " "  				 				 ! ! ! ! ! ! & & & & & & & & & &		8	$	$ ' ' ' ' ' '              9 8 8 8 8 8                                   $         
 1 0 0 0 0 0 C C C C C C C C C C
/ 
/ 
/ 
/ 
/3 3 3 3= = = =
5 5 5 5<& & & &RB B B B,61 61 61 61r" " " "J   .   ,8 8 8 8 8* #'	" " " " " ":      0 0 0 0   > +/%)"&P P P P P Pf    , (,#'	    @   0 0 0 0d d d dN   0 0 0 0j #%)< < < < < <~8 8 8 8, , , , '+'+	A A A A A AN '+'+	K K K K K Kd '+'+"&f f f f f f\ '+'+"&] ] ] ] ] ]D  $&*'+"&Z	 Z	 Z	 Z	 Z	 Z	z     r0   