
    Jjo                   n   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 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l/m0Z0 ddl1m2Z2m3Z3m4Z4 dZd[dZ5d\dZ6d]dZ7d^dZ8d_dZ9d`d Z:dad!Z;dbd"Z<dad#Z=dcd$Z>ddded'Z?dfd)Z@h d*ZAdgd-ZBdhd.ZCdid1ZDdddd2djd9ZEdddkd;ZF	 	 dldmd?ZGdndBZHdndCZIdodDZJdpdEZKd_dFZLdddGdqdIZMdhdJZNdrdLZOdddMdsdPZPdddMdtdQZQddddRdudSZRdddMdvdTZSdddddUdwdVZTdxdYZUdS )yzGShared runtime provider resolution for CLI, gateway, cron, and helpers.    )annotationsN)urlparse)AnyDictOptional)auth)CredentialPoolPooledCredential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      A/home/rurouni/.hermes/hermes-agent/hermes_cli/runtime_provider.py_getenvr.   +   s!     dG
$
$C/33w.    valuec                v    |                                                                                      dd          S )N -)striplowerreplacer0   s    r-   _normalize_custom_provider_namer8   8   s,    ;;==  ((c222r/   hostboolc                \    | pd                                                     d          }|dv S )Nr%   .>   ::10.0.0.0	localhost	127.0.0.1)r5   rstrip)r9   hs     r-   _loopback_hostnamerC   <   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.
    r%   FcustomTr   r   openrouter.ai)r4   r5   hermes_cli.authr   	Exceptionr"   rC   r#   )rD   rE   cfg_provider_normbu_resolve_providers        r-   ,_config_base_url_trustworthy_for_bare_customrO   A   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)r4   r5   rA   r#   r   pathendswith)rP   
normalizedhostnamerW   s       r-   _detect_api_mode_for_urlr[   _   s    * .b''))//1188==J **H:  ###  
 &&&##J$++C00D}}\"" $dmmO&D&D $##>!!i:&=&=##4r/   	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_moderT   zMIgnoring persisted custom api_mode=codex_responses for non-OpenAI endpoint %sz	(unknown)Nchat_completions)_parse_api_modegetr[   loggerinfo)r\   rP   configured_modedetected_modes       r-   _resolve_plain_custom_api_moderg      sz     &immJ&?&?@@O,X66M+++AR0R0R[#	
 	
 	
 AmA/AAr/   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::<<
:
:
:
:
:
:r/   r<   )r?   :c                    g | ]}||S  rs   )rm   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)isalnumrl   s     r-   ro   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isalphar.   r4   )rP   rZ   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0r/   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%   FrU   z.anthropic.comz.claude.comTz
.azure.comrV   )r4   r#   r5   rX   r[   )rP   	candidaterZ   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5r/   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   NrS   z/v1z/models   )timeoutdata   idz$Auto-detect model from %s failed: %s)
requestsrA   rX   rb   okjsonr   rK   rc   debug)rP   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%   rP   r?   r@   )r   rb   
isinstancedictr4   r   r'   )configr\   cfgr(   rP   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).
    r%   TrG   custom:)r4   r5   
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/   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   r%   r_   copilotr(   r`   r   )copilot_model_api_mode)r   )	r'   rb   r4   r5   ra   r   hermes_cli.modelsr   rK   )r\   r   r   re   
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>   rT   bedrock_converser`   codex_app_serverrV   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'   r4   r5   _VALID_API_MODES)r   rY   s     r-   ra   ra   Z  sD    #s YY[[&&((
)))4r/   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   rs   r/   r-   !_nous_inference_base_url_overrider   c  s     ())/R/r/   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'   rb   r4   r5   )r   r_   r\   runtimes       r-   %_maybe_apply_codex_app_server_runtimer   n  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           	     	   |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    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t1          |          }|r|}	| dv rddlm}  || |	|          }t5          | |	|          }	| dk    rt7          j        |          }| |	||t          |d d!          ||d"S )#Nr(   r%   runtime_base_urlrP   rS   runtime_api_keyaccess_tokenr`   r   rT   	xai-oauth
qwen-oauthminimax-oauthrV   	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normalize_opencode_base_url)r   r_   r\   lmstudiosourcer   )r   r_   rP   r   r   credential_poolr   )r   rb   getattrrA   r   r   r   r   inference_base_urlr'   r4   r5   r   r!   r   r   ra   r   r   rK   resubr   r   r[   r   r   auth_mod$_normalize_lmstudio_runtime_base_url)r   r   r   r\   r   r   effective_modelrP   r   r_   pconfigrE   rD   re   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		,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 $# 222AAAAAA..x8LL 5H	  H :@JJ %6220  s   $K6 6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)r4   r5   r   rb   r   r'   r.   )r   r\   rE   env_providers       r-   resolve_requested_providerr     s     )Y__&& )  &&(((!##I==,,L,$$ ,););)=)= ,!!##))+++ 6;;AACCIIKKL 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   r%   r`   zpool:)r   r_   rP   r   r   r   )r   r   has_credentialsselectr   r[   rK   )rP   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)rb   r   int)r   r  _k_vs       r-   _lift_max_output_tokensr	  J  sY     2  YYr]]b# 	266*,F&'FF	 r/   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    rb   )r   r  r  s      r-   _lift_extra_headersr  Y  s?     ,EIIo,F,FGGM 0"/0 0r/   c           	     b   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                    rE|                                D ]/\  }}t          |t                    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 1|                    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   rG   r   	providerskey_envr   rv   r   rP   r&   default_model)r&   rP   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&   rP   r   r   )r8   r   r   r   r4   r5   r   r   rb   r   r   itemsr'   r.   r  ra   r	  rc   warningr   )r   requested_norm	canonicalr   r  ep_namer   	name_normr  resolved_api_keyrP   r  r  r_   display_namedisplay_normr  r&   menu_keyr  provider_key_normprovider_menu_keyr   s                          r-   _get_named_custom_providerr!  d  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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!  rK   )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  rv   r   rP   r%   r   r&   )_normalize_base_url_for_matchr   rK   rb   r   r   r  r8   r'   r   r4   )	rP   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$)rP   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   rG   r   Nr   )r(  r'   r4   r   rb   rK   osenvironr8   r!  r   )rP   r)  identityr   candidate_norms        r-   canonical_custom_identityr/  E  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%   rS   )r'   r4   rA   r5   r7   s    r-   r%  r%    s:    u{!!##**3//55777r/   custom_providerc                    |                      d          }t          |t                    r|si S dt          |          iS )Nr  )rb   r   r   )r1  r  s     r-   "_custom_provider_request_overridesr3    sF     $$\22Jj$'' z 	$z**++r/   explicit_api_keyexplicit_base_urlr5  r6  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%   rG   r   rH   rS   zdirect-aliasr   
openai.comopenai.azure.comrI   OPENAI_API_KEYOPENROUTER_API_KEYc              3  8   K   | ]}t          |          |V  d S rj   r   )rm   cs     r-   ro   z0_resolve_named_custom_runtime.<locals>.<genexpr>  s0      CC1.?.B.BCQCCCCCCr/   no-key-requiredr`   r   r_   rP   r   r   r   rP   r_   r&   r   r   r  request_overridesr  r   r  c              3  8   K   | ]}t          |          |V  d S rj   r=  rm   r   s     r-   ro   z0_resolve_named_custom_runtime.<locals>.<genexpr>  s1      bb)EVW`EaEabIbbbbbbr/   zcustom_provider:r   r_   rP   r   r   )r4   r5   rJ   r   rK   rA   r   r"   r.   r   nextr[   r!  rb   r   r  r3  r   r'   )r   r5  r6  r  rN   rP   pool_result_da_is_openai_url_da_is_openrouterapi_key_candidatesr   r1  r   rA  _cp_is_openai_url_cp_is_openrouterr  s                    r-   _resolve_named_custom_runtimerL    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 )NrP   r%   r   )r   rv   rG   r   rH   r!   CUSTOM_BASE_URLFr   TrS   rI   r   r;  r:  z
ollama.comr8  r9  OLLAMA_API_KEYc              3  z   K   | ]6}t          |          t          |pd                                           V  7dS )r%   N)r   r'   r4   rC  s     r-   ro   z._resolve_openrouter_runtime.<locals>.<genexpr>z  sI      jj)M^_hMiMijY_"			#	#	%	%jjjjjjr/   explicitz
env/configr_   r   r?  r`   rD  )r   r   rb   r'   r4   r5   rJ   r   rK   r.   rO   r!   rA   r"   r   rE  r   ra   rg   r[   )r   r5  r6  r\   rD   rE   cfg_api_keykvr  rN   env_openrouter_base_urlenv_custom_base_urluse_config_base_urlrP   _is_openrouter_url_is_openrouter_contextrI  _is_ollama_url_is_openai_url_is_openai_azurer   r   effective_providerrF  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	 &&;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$)r5  r6  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%   rS   r   r`   r   r   rP   r_   	auth_modeentrar(   rV   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_idrQ  )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)rh  )r   )r   r_   rP   r   r`  ra  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_   rP   r   r`  r   r   )r'   r4   rA   rb   r5   ra   r   r   r   r   rK   r.   r   r   r   agent.azure_identity_adapterrd  re  rf  ImportErrorhermes_cli.configri  )r   r\   r5  r6  r   explicit_base_url_cleanrE   rD   cfg_api_modecfg_auth_mode	cfg_entra_entrar   r   r   env_base_urlrP   r   r   r`  rd  re  rf  r   rh  entra_configtoken_providerclean_entraconfigured_scoperi  s                                 r-   _resolve_azure_foundry_runtimerx    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        |           }|re|j        dk    rYd}|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%   rS   r   r   rP   r   r   resolve_anthropic_tokenNo Anthropic credentials found. Set ANTHROPIC_TOKEN or ANTHROPIC_API_KEY, run 'claude setup-token', or authenticate with 'claude /login'.rV   rQ  r@  r   r   last_refreshrT   r   r_   rP   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_secondsr`   r   r_   rP   r   r   r  r   r   )r   r\   r5  r6  >   kimi-codingkimi-coding-cnr   r   r_   )r'   r4   rA   rb   r5   r   agent.anthropic_adapterr{  r   r   r   r   get_provider_auth_stater   DEFAULT_NOUS_INFERENCE_URLr   maxr$   r   floatr.   rx  r   	auth_typebase_url_env_varr   r   r   ra   r[   )r   r   r\   r5  r6  rE   rD   rP   r   r{  r}  credsstater  r   env_urlr_   re   r   s                      r-   _resolve_explicit_runtimer  J  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GDDHH(HH-immJ.G.GHHO (* 4H== ('H !  ,, "4
 
 	
 4r/   )r   r5  r6  r   c           
     
  7 t          |           }|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                                          77r:|dv r6d}t          7fd|D                       st          |||          }||d<   |S t          |||          }t                      }t!          |||||          }|r|S |dk    }|dk    rt          |                    d          pd                                                                          }t          |                    d          pd                                          7t          d d                                          }t          d!d                                          }t#          |p|p|          }7r|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    rO|Lt/          d)t1          d*d+                    }t-          |d,d%          t-          |d-d%          t-          |d.d%          d/}t3          ||          st4                              d0           	 |                                }n4# t&          $ r'}t4                              d1|           d%}Y d%}~nd%}~ww xY w|W|}t-          |d&d%          pt-          |d'd          }t-          |d,d%          t-          |d-d%          t-          |d.d%          d/}|rt3          ||          st4                              d2           d}||rt;          ||||||3          S |d(k    r	 t=          t?          t          d4d5                    6          }d(d|                    dd                              d          |                    d7d          |                    d8d9          |                    d:          |d;S # t          $ r$ |d<k    r t4                               d=           Y nw xY w|d>k    r	 tC                      }d>d?|                    dd                              d          |                    d7d          |                    d8d@          |                    dA          |dBS # t          $ r$ |d<k    r t4                               dC           Y nw xY w|dDk    r	 tE                      }dDd?|                    d          pd                    d          ptF          |                    d7d          |                    d8d@          |                    dA          |dBS # t          $ r$ |d<k    r t4                               dE           Y nw xY w|dFk    r	 tI                      }dFd|                    dd                              d          |                    d7d          |                    d8dG          |                    dH          |dIS # t          $ r$ |d<k    r t4                               dJ           Y nw xY w|dKk    rZtK          j        |          }|rD|j&        dLk    r9ddMl'm(}   |             }|d|d         |d7         |                    d8dN          |dS |dOk    rtS          |          }dOd|                    dd                              d          |                    d7d          |                    dPd          tU          |                    dQ          pg           |                    d8dR          |dSS |dk    rt          |                    d          pd                                                                          }d7|dk    rM|                    d          pd                                                    d          7tW          7          sd77pdT}
d|
                                v p7od7                                v }!|!rd}	dUD ]`}"t          |                    |"          pd                                          }#|#r&t          |#d                                          }	|	r na|	s6t          |                    d7          pd                                          }	|	sDt          d	d                                          p!t          d
d                                          }	|	st          dV          n!ddWl,m-}$  |$            }	|	st          dX          dd|
|	dY|dS |dZk    rdd[l.m/}%m0}&m1}'m2}( |d\v })|)s |%            st          d]d^_          tg                                          dZi           }*|*                    d`          pd                                p	 |'            }+ |&            pda},|*                    dbi           }-d%}.|-                    dc          rf|-                    dd          rQ|-dc         |-dd         de}.|-                    df          r|-df         |.dg<   |-                    dh          r|-dh         |.dh<   t          |p|                    di          pd                                          }/ |(|/          rdZddj|+ dkdl|,|+d#|dm}ndZdndj|+ dkdl|,|+|do}|.r|.|dp<   |S tK          j        |          }|r+|j&        d7k    rti          |          }t          |                    d          pd                                                                          }d7||k    r<|                    d          pd                                                    d          77p(|                    dd                              d          }
d}0|dqk    r%tk          ||                    d7d                    }0n|drk    rd?}0nt          |                    d          pd                                                                          }1tm          |                    ds                    }2|dtv r+ddul7m8}3 |p|                    did          }4 |3||4          }0n(|2rts          ||1          r|2}0ntu          |
          }5|5r|5}0|dtv rddvl7m;}6  |6||0|
          }
|dwk    rty          j=        |
          }
||0|
|                    d7d          |                    d8dY          |dS t          |||          }||d<   |S )xa)  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).
    moar`   zmoa://localzmoa-virtual-providerr@  r%   r   z	azure.comAZURE_ANTHROPIC_KEYANTHROPIC_API_KEYrV   rS   zazure-explicitr   )r   r\   r5  r6  r   )vertexzgoogle-vertexz	vertex-aiz
gcp-vertexvertexair   )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. Install the extra with: pip install 'hermes-agent[vertex]'.r  zvertex-oauth)r   r5  r6  r   r   rP   )r   r%   )rI   zanthropic.comr8  c              3  8   K   | ]}t          |          V  d S rj   )r"   )rm   r9   rD   s     r-   ro   z+resolve_runtime_provider.<locals>.<genexpr>h  sA         &lD99     r/   r4  )r   r   r\   r5  r6  r   OPENAI_BASE_URLr!   >   r   rG   T>   r   r   Nr   r   r   r  r  r  r  r  rh  )r  r  rh  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 resolution)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   rT   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_   rP   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_   rP   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.rz  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(   zhttps://bedrock-runtime.z.amazonaws.comzaws-sdk)r   r_   rP   r   r   r  bedrock_anthropicr   r   )r   r_   rP   r   r   r  r   guardrail_configr   r   r_   r   r   r   r   )>r   r4   r.   rA   rx  r   agent.vertex_adapterr  r   rL  r'   rb   r5   r   r^  r   r  r:   r   rK   r   r   r   r  r$   r   rc   r   try_refresh_currentr   r   r  rd   r   r   r   r   r   r  rJ   r  r   listr   r  r{  agent.bedrock_adapterr  r  r  r  r   r   r   ra   r   r   r   r[   r   r   r   )8r   r5  r6  r   r   	_eff_base
_azure_keyazure_runtimer  tokenrP   custom_runtimer\   rE   _known_cloud_hostsr   r   explicit_runtimeshould_use_poolenv_openai_base_urlrU  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_modelr_   r   re   r   
_effectiver   r   rD   s8                                                          @r-   resolve_runtime_providerr    s   " 4I>>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 		N   !* ,,$"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    2$$&& 2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3!#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%%n55 	 &0MvMMM$% %)&8	 	GG &.MvMMM$% &8 G  	;*:G&'  #H--G 6
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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   M M+*M+Q 
R%RR6BW +W;:W;A9Y? ?+Z-,Z-7B\9 9+]'&]'1A9_+ ++``errorrK   c                h    t          | t                    rt          |           S t          |           S rj   )r   r   r   r'   )r  s    r-   format_runtime_provider_errorr    s.    %## ( '''u::r/   )r%   )r&   r'   r(   r'   r)   r'   )r0   r'   r)   r'   )r9   r'   r)   r:   )rD   r'   rE   r'   r)   r:   )rP   r'   r)   rQ   )r\   r]   rP   r'   r)   r'   )rP   r'   r)   r'   )rP   r'   r)   r:   )r)   r]   rj   )r   rQ   r   rQ   r)   r:   )r\   r]   r   r'   r)   r'   )r   r   r)   rQ   )r)   r'   )r   r'   r_   r'   r\   r   r)   r'   )r   r'   r   r
   r   r'   r\   r   r   r   r   rQ   r)   r]   )r   rQ   r)   r'   )NN)
rP   r'   r   r'   r   rQ   r   rQ   r)   r   )r   r]   r  r]   r)   r  )r   r'   r)   r   )r   r'   r)   r:   )rP   rQ   r)  rQ   r)   rQ   )r1  r]   r)   r]   )r   r'   r5  rQ   r6  rQ   r)   r   )r   r'   r5  rQ   r6  rQ   r)   r]   )r   r'   r\   r]   r5  rQ   r6  rQ   r   rQ   r)   r]   )r   r'   r   r'   r\   r]   r5  rQ   r6  rQ   r)   r   )
r   rQ   r5  rQ   r6  rQ   r   rQ   r)   r]   )r  rK   r)   r'   )V__doc__
__future__r   loggingr+  r   urllib.parser   typingr   r   r   	getLogger__name__rc   
hermes_clir   r   agent.credential_poolr	   r
   r   r   agent.secret_scoper   r+   rJ   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rm  r   r   r    hermes_constantsr!   utilsr"   r#   r$   r.   r8   rC   rO   r[   rg   r   r   r   r   r   r   r   ra   r   r   r   r   r   r	  r  r!  r#  r(  r/  r%  r3  rL  r^  rx  r  r  r  rs   r/   r-   <module>r     sU   M M " " " " " "  				 				 ! ! ! ! ! ! & & & & & & & & & &		8	$	$ ' ' ' ' ' ' k k k k k k k k k k k k 8 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   > +/%)"&L L L L L L^    , (,#'	    @   0 0 0 0] ] ] ]@   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\ '+'+X X X X X Xz  $&*'+"&_ _ _ _ _ _D     r/   