
    `gj{                      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 d3d4dZ6d5dZ7d6dZ8d7dZ9d8dZ:d9dZ;d:dZ<d;dZ=d:dZ>d<dZ?d=d>dZ@d?dZAh dZBd@dZCdAdZD	 	 	 	 	 	 	 	 dBdZEdddd	 	 	 	 	 	 	 	 	 	 	 	 	 dCdZFd=dDdZG	 	 dE	 	 	 	 	 	 	 	 	 dFd ZHdGd!ZIdGd"ZJdHd#ZKdId$ZLd8d%ZMddd&	 	 	 	 	 dJd'ZNdAd(ZOdKd)ZPddd*	 	 	 	 	 	 	 dLd+ZQddd*	 	 	 	 	 	 	 dMd,ZRdddd-	 	 	 	 	 	 	 	 	 	 	 dNd.ZSddd*	 	 	 	 	 	 	 	 	 	 	 dOd/ZTddddd0	 	 	 	 	 	 	 	 	 dPd1ZUdQd2ZVy)RzGShared 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_intc                &    t        | |      }||S |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)namedefaultvals      N/root/.hermes/venv/lib/python3.12/site-packages/hermes_cli/runtime_provider.py_getenvr,   1   s     dG
$C/3.w.    c                ^    | j                         j                         j                  dd      S )N -)striplowerreplacevalues    r+   _normalize_custom_provider_namer6   >   s$    ;;= ((c22r-   c                P    | xs dj                         j                  d      }|dv S )N .>   ::10.0.0.0	localhost	127.0.0.1)r2   rstrip)hosths     r+   _loopback_hostnamerA   B   s+    	##C(A<<<r-   c                   |xs dj                         j                         }| xs dj                         }|sy|dk(  ry	 ddlm}  ||      dk(  ry	 t        |d      ryt        t        |            S # t        $ r Y ,w xY w)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.
    r8   FcustomTr   r   openrouter.ai)r1   r2   hermes_cli.authr   	Exceptionr#   rA   r$   )cfg_base_urlcfg_providercfg_provider_normbu_resolve_providers        r+   ,_config_base_url_trustworthy_for_bare_customrM   G   s     &+224::<

"	#	#	%BH$
I./8; < R1/344	  s   A5 5	B Bc                B   | xs dj                         j                         j                  d      }t        |       }|dk(  ry|dk(  ry|dk(  ryt	        |      j
                  j                  d      }|j                  d      s|j                  d	      ry|d
k(  rd|v ryy)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).
    r8   /zapi.x.aicodex_responseszapi.openai.comapi.anthropic.comanthropic_messagesz
/anthropicz/anthropic/v1zapi.kimi.comz/codingN)r1   r2   r>   r$   r   pathendswith)base_url
normalizedhostnamerS   s       r+   _detect_api_mode_for_urlrX   e   s    * .b'')//188=J *H: ## 
 &&#J$$++C0D}}\"dmmO&D#>!i:&=#r-   c                    t        | j                  d            }t        |      }|dk(  r!|dk7  rt        j	                  d|xs d       d}|xs |xs 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_moderP   zMIgnoring persisted custom api_mode=codex_responses for non-OpenAI endpoint %sz	(unknown)Nchat_completions)_parse_api_modegetrX   loggerinfo)	model_cfgrU   configured_modedetected_modes       r+   _resolve_plain_custom_api_moderc      sa     &immJ&?@O,X6M++AR0R[#	
 AmA/AAr-   c                   t        |       }|syt        d |j                  d      d   D              ry|dv sd|v ry|j                  d      D cg c]  }|s|	 }}|r"|d   dv r|j                  d       |r|d   dv rt	        |      d	k  ry|d
   }dj                  d |D              j                         }|r|d   j                         sy|dv ry| d}t        |d      xs dj                         S c c}w )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).
    r8   c              3  <   K   | ]  }|j                           y wN)isdigit.0chs     r+   	<genexpr>z(_host_derived_api_key.<locals>.<genexpr>   s     
:B2::<
:s   r9   )r<   :r   )apiwww   c              3  D   K   | ]  }|j                         r|nd   yw)_N)isalnumrh   s     r+   rk   z(_host_derived_api_key.<locals>.<genexpr>   s     Ebjjl3Es    )OPENAI
OPENROUTEROLLAMA_API_KEY)
r$   anysplitpoplenjoinupperisalphar,   r1   )rU   rW   lbllabelsvendor	sanitizedenv_names          r+   _host_derived_api_keyr      s   & !*H

:(.."5b"9
::>!SH_%^^C08cCc8F8
VAY.0

1 VAY.0
6{Q BZFEfEEKKMIIaL00266H%HHb!'R..005 9s   C:C:c                   | xs dj                         }|syt        |      xs dj                         }|sy|dk(  s"|j                  d      s|j                  d      ry|j                  d      ryt	        |      dk(  ryy)	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``.
    r8   FrQ   z.anthropic.comz.claude.comTz
.azure.comrR   )r1   r$   r2   rT   rX   )rU   	candidaterW   s      r+   _anthropic_base_url_override_okr      s     R&&(I!),299;H &&(*;*;<L*MQYQbQbcpQq&  	*.BBr-   c                   | sy	 ddl }| j                  d      }|j                  d      s|dz  }|j                  |dz   d      }|j                  rG|j                         j                  d	g       }t        |      d
k(  r|d   j                  dd      }|r|S y# t        $ r!}t        j                  d| |       Y d}~yd}~ww xY w)zFQuery a local server for its model name when only one model is loaded.r8   r   NrO   z/v1z/models   )timeoutdata   idz$Auto-detect model from %s failed: %s)
requestsr>   rT   r]   okjsonr|   rG   r^   debug)rU   r   urlrespmodelsmodel_idexcs          r+   _auto_detect_local_modelr     s    Looc"||E"5LC||C)OQ|777YY[__VR0F6{a!!9==r2#O
 	  L 	;XsKK	Ls   BB 	C#B??Cc                    t               } | j                  d      }t        |t              rt        |      }|j                  d      s|j                  d      r|d   |d<   |j                  d      xs dj	                         }|j                  d      xs dj	                         }d|v xs d|v }| }|r|r|rt        |      }|r||d<   |S t        |t              r"|j	                         rd|j	                         iS i S )Nmodelr)   r8   rU   r<   r=   )r    r]   
isinstancedictr1   r   str)configr`   cfgr)   rU   is_localis_fallbackdetecteds           r+   _get_model_configr     s    ]F

7#I)T"9owwy!cggg&6 \C	N779%+224GGJ'-2446(*EkX.E!k/9H!)I
)S!ioo&79??,--Ir-   c                    | xs dj                         j                         }|xs dj                         j                         }|sy|dk(  r|dk(  xs |j                  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).
    r8   TrC   custom:)r1   r2   
startswith)providerconfigured_providernormalized_providernormalized_configureds       r+   $_provider_supports_explicit_api_moder   /  st     $>r00288:06B==?EEG h&$0_4I4T4TU^4__ $777r-   c                h   t        | j                  d      xs d      j                         j                         }t	        | j                  d            }|rt        d|      r|S t        | j                  d      xs d      j                         }|sy	 ddlm}  |||	      S # t        $ r Y yw xY w)
Nr   r8   rZ   copilotr)   r[   r   )copilot_model_api_mode)api_key)	r   r]   r1   r2   r\   r   hermes_cli.modelsr   rG   )r`   r   r   ra   
model_namer   s         r+   _copilot_runtime_api_moder   @  s    immJ7=2>DDFLLN%immJ&?@O?	K^_Y]]9-34::<J!"<%j'BB "!"s   B% %	B10B1>   rP   bedrock_converser[   codex_app_serverrR   c                t    t        | t              r(| j                         j                         }|t        v r|S y)z@Validate an api_mode value from config. Returns None if invalid.N)r   r   r1   r2   _VALID_API_MODES)rawrV   s     r+   r\   r\   `  s2    #sYY[&&(
))r-   c                     t               xs 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.
    r8   )r    r-   r+   !_nous_inference_base_url_overrider   i  s     ()/R/r-   c                    |s|S | dvr|S t        |j                  d      xs d      j                         j                         }|dk(  ry|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_runtimer8   r   )r   r]   r1   r2   )r   rZ   r`   runtimes       r+   %_maybe_apply_codex_app_server_runtimer   t  sV      11)-- 017R8>>@FFHG$$!Or-   )r`   pooltarget_modelc           	     f   |xs
 t               }|xs |j                  d      xs d}t        |dd       xs t        |dd       xs dj                  d      }t        |dd       xs t        |dd      }d}	| d	k(  rd
}	|xs t        }nH| dk(  rd
}	|xs t
        }n5| dk(  rd}	|xs t        }n"| dk(  r-d}	t        j                  |       }
|xs |
r|
j                  nd}n| dk(  rd}	t        |j                  d      xs d      j                         j                         }d}|dk(  rHt        |j                  d      xs d      j                         j                  d      }t        |      sd}|xs |xs d}nT| dk(  r|xs t        }nC| dk(  rd
}	n:| dk(  rd}	t               xs |}n#| dk(  r0t        |t        |dd            }	|xs t        d   j                  }n| dk(  rt        |j                  d      xs d      j                         j                         }|dk(  r]t        |j                  d      xs d      j                         j                  d      }|r|}t!        |j                  d            }|r|}	|r|	dk7  r	 ddlm}  ||      }|r|}	|	dk(  r-t)        j*                  dd|      }nt        |j                  d      xs d      j                         j                         }t        j                  |       }
|
xr- |j                  d      |
j                  j                  d      k(  }|| k(  rA|r?t        |j                  d      xs d      j                         j                  d      }|r|}t!        |j                  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        j8                  |      }| |	||t        |d d!      ||d"S # t&        $ r d }Y w xY w)#Nr)   r8   runtime_base_urlrU   rO   runtime_api_keyaccess_tokenr[   r   rP   	xai-oauth
qwen-oauthminimax-oauthrR   	anthropicr   https://api.anthropic.com
openrouterxainousr   azure-foundryrZ   r   azure_foundry_model_api_mode/v1/?$   opencode-goopencode-zenopencode_model_api_modenormalize_opencode_base_url)r   rZ   r`   lmstudiosourcer   )r   rZ   rU   r   r   credential_poolrequested_provider)r   r]   getattrr>   r   r   r   r   inference_base_urlr   r1   r2   r   r"   r   r   r\   r   r   rG   resubr   r   rX   r   r   auth_mod$_normalize_lmstudio_runtime_base_url)r   entryr   r`   r   r   effective_modelrU   r   rZ   pconfigrI   rH   ra   r   inferredr   pool_url_is_defaultr   r   r   s                        r+    _resolve_runtime_from_pool_entryr     sI    0.0I $Ey}}Y'?E2O148bGE:W[<\b`bjjknoHe.5[XZ9[G!H>!$55	[	 $99	\	!%44	_	$
 (#''1Ng : :2	[	 '9==4:;AACIIK;&y}}Z8>B?EEGNNsSL2<@!J8J/J	\	!22	U	$	V	%46B(	Y	,YGXZ\8]^N0;NN	_	$9==4:;AACIIK?*y}}Z8>B?EEGNNsSL'-immJ.GHO*
 x+?? J7H #++vviX6H!)--
";"ArBHHJPPR
 $''1%h(//#*>'B\B\BcBcdgBh*h(*/By}}Z8>B?EEGNNsSL'))--
*CD66 B.xIH!EhPc!d&H
 09H# 22A.x8L 5H	H :@@J %620 s    s   P! !P0/P0c                n   | r.| j                         r| j                         j                         S t               }|j                  d      }t	        |t
              r.|j                         r|j                         j                         S t        dd      j                         j                         }|r|S y)z=Resolve provider request from explicit arg, config, then env.r   HERMES_INFERENCE_PROVIDERr8   auto)r1   r2   r   r]   r   r   r,   )	requestedr`   rI   env_providers       r+   resolve_requested_providerr     s    Y__& &&((!#I==,L,$););)=!!#))++ 6;AACIIKLr-   c                   t        | |      }|sy	 t        |      }|j                         sy|j                         }|yt	        |dd      xs t	        |dd      }|sy||xs t        |       xs d| |d| |dS # t        $ r Y yw xY w)	zXCheck if a credential pool exists for a custom endpoint and return a runtime dict if so.provider_nameNr   r   r8   r[   zpool:)r   rZ   rU   r   r   r   )r   r   has_credentialsselectr   rX   rG   )rU   provider_labelapi_mode_overrider   pool_keyr   r   pool_api_keys           r+   _try_resolve_from_custom_poolr   0  s     ,HMRH"##%=u&7>d'%Q_acBd&)e-Eh-OeSe #hZ(#
 	
  s"   A= A= A=  A= =	B	B	c                n    dD ]0  }| j                  |      }t        |t              s%|dkD  s+||d<    y y)aq  Propagate a per-provider output cap onto the resolved runtime dict.

    Accepts ``max_output_tokens`` or ``max_tokens`` on a ``custom_providers``
    entry so a provider block can pin its own output limit. Gateway and CLI
    map this onto ``AIAgent.max_tokens`` only when the top-level
    ``model.max_tokens`` isn't set, so the documented global key still wins.
    )max_output_tokens
max_tokensr   r   N)r]   r   int)r   result_k_vs       r+   _lift_max_output_tokensr  P  s>     2 YYr]b#26*,F&'	r-   c                H    t        | j                  d            }|r||d<   yy)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!   r]   )r   r   r  s      r+   _lift_extra_headersr  _  s)     ,EIIo,FGM"/ r-   c           	     ,   t        | xs d      }|sy |dk(  ry |dk7  rM|j                  d      s<	 t        j                  |      }|xs dj	                         j                         |k(  ry t               }|j                  d      }t        |t              rddlm} |j                         D ]  \  }}t        |t              s ||      s!t        |      }t        |j                  dd      xs d      j	                         }	|	rt        |	d      j	                         nd}
|
s-t        |j                  d	d      xs d      j	                         }
|||d| hv r|j                  d
      xs( |j                  d      xs |j                  d      xs d}|r|j                  d|      |j	                         |
|j                  dd      d}|j                  d      }t        |t              rt        |      |d<   t!        ||       t#        |j                  d      xs |j                  d            }|r||d<   t%        ||       |c S |j                  dd      }|st        |      }|||d| hv s|j                  d
      xs( |j                  d      xs |j                  d      xs d}|s||j	                         |
|j                  dd      d}|j                  d      }t        |t              rt        |      |d<   t!        ||       t#        |j                  d      xs |j                  d            }|r||d<   t%        ||       |c S  |j                  d      }t        |t              rt&        j)                  d       y t+        |      }|sy |D ]  }t        |t              s|j                  d      }|j                  d      }t        |t              rt        |t              sXt        |      }d| }t        |j                  dd      xs d      j	                         }|rt        |      nd}|rd| nd}|||||hvr|j	                         |j	                         t        |j                  d	d      xs d      j	                         d}t        |j                  dd      xs d      j	                         }	|	r|	|d<   |r||d<   |j                  d      }t        |t              rt        |      |d<   t!        ||       t#        |j                  d            }|r||d<   t        |j                  dd      xs d      j	                         }|r||d<   t%        ||       |c S  y # t        $ r Y 'w xY w)Nr8   r   rC   r   	providersr   )is_provider_enabledkey_envr   rn   r   rU   r(   default_model)r(   rU   r   r   
extra_bodyrZ   	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(   rU   r   r   )r6   r   r   r   r1   r2   r   r    r]   r   r   hermes_cli.configr  itemsr   r,   r  r\   r  r^   warningr   )r   requested_norm	canonicalr   r  r  ep_namer   	name_normr  resolved_api_keyrU   r   r
  rZ   display_namedisplay_normr  r(   menu_keyr  provider_key_normprovider_menu_keyr   s                           r+   _get_named_custom_providerr  j  sP   45G5M2NN" !.*C*CI*N	 11.AI R&&(..0NB]F 

;'I)T"9'oo/ B	&NGUeT*
 'u-7@I%))Ir28b9??AG?Fww399;B##&uyyB'?'E2#F#L#L#N '9	{6K!LL 99U+^uyy/?^599ZCX^\^ %		&' :$,NN$4#3!&?B!?	F "'<!8J!*d3/3J/?|,'v6  /uyy/D/^		R]H^_H-5z*+E6:!M 99VR0L>|L!lLGL>BZ%[[$yy/b599U3CbuyyQ[G\b`bH$0(0(8'7%*YY%C	" &+YY|%<
%j$737
3CF<0+E6:#2599Z3H3bEIIVaLb#c#19F:./v>%EB	&J zz"45"D)/	

 6v>! #%&yy 99Z($$Jx,E3D9	YK(599^R8>B?EEGMY;LI_a=Ng&7%89TV)X7HJ[!\\JJL (599Y39r:@@B

 eii	2.4"5;;= 'F9%1F>"YY|,
j$'#'
#3F< E6*"599Z#89!)F:7B/526<<>
(F7Ov.G#J W  		s   V 	VVc                <    	 t        |       duS # t        $ r Y y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  rG   )r   s    r+   has_named_custom_providerr    s*    )*<=TII s    	c                   t        |       }|sy	 t               }|j                  d      }t	        |t
              r|j                         D ]x  \  }}t	        |t
              s|j                  d      xs( |j                  d      xs |j                  d      xs d}t        |      |k(  sadt        t        |             c S  	 t        |      }|xs g D ]r  }t	        |t
              s|j                  d      }t	        |t              r|j                         sFt        |j                  d            |k(  sddt        |       c S  y# t        $ r Y yw xY w# t        $ r d}Y w xY w)	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  rn   r   rU   r8   r   r(   )_normalize_base_url_for_matchr    rG   r]   r   r   r  r6   r   r   r1   )	rU   targetr   r  r  r   	entry_urlr  r(   s	            r+   find_custom_provider_identityr"    sn     +84F 

;'I)T"'oo/ 	QNGUeT*		% SEIIe$4S		*8MSQS  -Y76A !@W!N OPP	Q :6B "'R E%&yy $$DJJL(:)>?6I<TBCDDE 7       s#   
E E 	EEE+*E+)rU   config_providerc                   | rt        |       }|r|S t        |xs d      j                         }|s5	 t        t               j	                  d      xs d      j                         }|s.t        j                  j	                  dd      j                         }t        |      }|r|dv ry	 t        |      |j                  d      r|S d| S 	 y# t
        $ r d}Y uw xY w# t
        $ r Y yw xY w)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).
    r8   r   r   >   r   rC   r   Nr   )r"  r   r1   r   r]   rG   osenvironr6   r  r   )rU   r#  identityr   candidate_norms        r+   canonical_custom_identityr)  R  s   @ 0:O O)r*002I	-/33J?E2FLLNI JJNN#>CIIK	4Y?N^/OO%i0<((3%%^,-- = %  	I	   s)   4C )C C CC	C+*C+c                v    t        | xs d      j                         j                  d      j                         S )Nr8   rO   )r   r1   r>   r2   r4   s    r+   r  r    s.    u{!!#**3/5577r-   c                f    | j                  d      }t        |t              r|si S dt        |      iS )Nr
  )r]   r   r   )custom_providerr
  s     r+   "_custom_provider_request_overridesr-    s3     $$\2Jj$'z	$z*++r-   explicit_api_keyexplicit_base_urlc           
        | xs dj                         j                         }|r|dk7  r	 ddlm}  ||      dk(  rd}|dk(  r|r|j                         j                  d      }t        |dd       }|rd|d<   |S t        |d      xs t        |d	      }t        |d
      }|xs dj                         |rt        dd      j                         nd|rt        dd      j                         ndt        |      g}	t        d |	D        d      xs d}
dt        |      xs d||
d| dS t        |       }|sy |xs dj                         xs |j                  dd      j                  d      }|sy t        |d|j                  d      |j                  d            }|r|j                  d      }|r||d<   t        |j                  d      t              r|d   |d<   t!        |      }|r%i t#        |j                  d      xs i       ||d<   |j                  d      rt#        |d         |d<   |S t        |d      xs t        |d	      }t        |d
      }|xs dj                         t%        |j                  dd      xs d      j                         t        t%        |j                  dd      xs d      j                         d      j                         |rt        dd      j                         nd|rt        dd      j                         ndt        |      g}	t        d |	D        d      }
d|j                  d      xs t        |      xs d||
xs dd|j                  d|        d}|j                  d      r|d   |d<   t        |j                  d      t              r|d   |d<   |j                  d      rt#        |d         |d<   t!        |      }|r||d<   |S # t        $ r Y w xY w)Nr8   rC   r   rD   rO   zdirect-aliasr   
openai.comopenai.azure.comrE   OPENAI_API_KEYOPENROUTER_API_KEYc              3  8   K   | ]  }t        |      s|  y wrf   r   )ri   cs     r+   rk   z0_resolve_named_custom_runtime.<locals>.<genexpr>  s     C1.?.BQC   no-key-requiredr[   r   rZ   rU   r   r   r   rU   rZ   r(   r   r   r   request_overridesr  r   r  c              3  8   K   | ]  }t        |      s|  y wrf   r7  ri   r   s     r+   rk   z0_resolve_named_custom_runtime.<locals>.<genexpr>  s     b)EVW`EaIbr9  zcustom_provider:r   rZ   rU   r   r   )r1   r2   rF   r   rG   r>   r   r#   r,   r   nextrX   r  r]   r   r   r-  r   r   )r   r/  r0  r  rL   rU   pool_result_da_is_openai_url_da_is_openrouterapi_key_candidatesr   r,  r   r<  _cp_is_openai_url_cp_is_openrouterr   s                    r+   _resolve_named_custom_runtimerG    s    ).B557==?N.H4	M 0H<!) !&7$**,33C8 4HhM$2K!3HlK  COdem  pB  PC3HoN#**,:KW%r*002QS:KW)2.446RT "(+	
 C*C
   	
 !0:P>P $"4
 	
 11CDO 
	 b'') 	/z2.fSk   0(ODWDWXbDc  tC  tG  tG  HN  tO  PK %((1
#-K o))*=>D/>?R/SK+,>O0{':;ArB0#0K+, /+/0P+QK(/,G~K`aik}K~//J		R&&(O	2.4"5;;=O''	26<"=CCErJPPR 7H!2	&	,	,	.b6G%r	*	0	0	2b 	h' b/AbdfgG #''
3 #H-//$_%8%8AS%T$UVF 7#)'2w/%%&9:C@&56I&J"# ?+"&'G"H:?K&7"#MY  		s   O) )	O65O6c           	     t   t               }t        |j                  d      t              r|j                  d      nd}t        |j                  d      t              r|j                  d      nd}d}dD ]F  }|j                  |      }t        |t              s%|j	                         s6|j	                         } n | xs dj	                         j                         }	|j	                         j                         }|	r|	dk7  r	 ddlm}
  |
|	      dk(  rd}	t        dd      j	                         }t        d	d      j	                         }d
}|j	                         r$|s"|	dk(  r
|r|dk(  rd}n|	dk(  rt        ||      rd}|xs dj	                         xs$ |xs  |r|j	                         ndxs
 |xs t        j                  d      }t        |d      }|xs* |	dk(  xr# |xs ||k(  xr ||xs dj                  d      k(  }|r|t        d      t        d      g}nbt        |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(  r4|r2t!        ||t#        |j                  d            |	dk7  r| nd       }|r|S |dk(  r|s|sd}||dk(  rt%        ||      n*t#        |j                  d            xs t'        |      xs d|||dS # t        $ r Y w xY w)NrU   r8   r   )r   rn   rC   r   rD   r"   CUSTOM_BASE_URLFr   TrO   rE   r   r5  r4  z
ollama.comr2  r3  OLLAMA_API_KEYc              3  n   K   | ]-  }t        |      st        |xs d       j                          / yw)r8   N)r   r   r1   r>  s     r+   rk   z._resolve_openrouter_runtime.<locals>.<genexpr>  s+     j)M^_hMiY_"		#	#	%js   5"5explicitz
env/configrZ   r   r:  r[   r?  )r   r   r]   r   r1   r2   rF   r   rG   r,   rM   r"   r>   r#   r   r@  r   r\   rc   rX   )r   r/  r0  r`   rH   rI   cfg_api_keykvr  rL   env_openrouter_base_urlenv_custom_base_urluse_config_base_urlrU   _is_openrouter_url_is_openrouter_contextrD  _is_ollama_url_is_openai_url_is_openai_azurer   r   effective_providerrA  s                            r+   _resolve_openrouter_runtimerY     s    "#I0:9==;TVY0Z9==,`bL0:9==;TVY0Z9==,`bLK MM!a!'')'')K	
 ).B557==?N%%'--/L .H4	M 0H<!) &&;R@FFH!"3R8>>@
  $5V#<6#9&*#x',X,-
 #' 
	 b'') 		$7L R	 #	 fSk  /xI 0 ,& 	D$K4K(K	D06B>>sCC 
 ()$%
 2(LI1(LI1(<NO /[R.<W%&XZ/=AQW%&XZ.@W)*XZ
 "(+
 j7Ij
G
 -0AZF &4x%?\ X%( 4(/)--
:S*T0>(0J,PT
 X%g>P# ') 39hGY]]:67 #H-
 
K  		s   L* *	L76L7)r/  r0  r   c           	        t        |xs d      j                         }t        |xs d      j                         j                  d      }t        |j                  d      xs d      j                         j	                         }d}d}d}	i }
|dk(  rt        |j                  d      xs d      j                         j                  d      }t        |j                  d            xs d}t        |j                  d	      xs d      j                         j	                         xs d}	|j                  d
      }t        |t              r|}
t        |xs |j                  d      xs d      j                         }|r|dk7  r	 ddlm	}  ||      }|r|}t        dd      j                         j                  d      }|xs |xs |}|st        d      |dk(  rt        j                  dd|      }|	dk(  r|r|}d}d}nT	 ddlm}m}m} t        |
j                  d      xs d      j                         xs |}	  ||      } ||      }|}d}d}i }|dk(  r3t        |
j                  d      xs d      j                         }|r||d<   d||||||| dS |}|s	 ddlm}  |d      xs d}|st        dd      j                         }|st        d      |s|rdnd}d|||d|| d S # t        $ r d}Y gw xY w# t        $ r}t        d| d      |d}~ww xY w# t&        $ r}t        t        |            |d}~ww xY w# t        $ r d}Y w xY w)!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.
    r8   rO   r   r[   r   r   rU   rZ   	auth_modeentrar)   rR   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_idrL  )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)rc  )r   )r   rZ   rU   r   r[  r\  r   r   )get_env_valueAZURE_FOUNDRY_API_KEYa  Azure Foundry requires an API key. Set AZURE_FOUNDRY_API_KEY in ~/.hermes/.env or run 'hermes model' to configure. To use keyless Microsoft Entra ID auth instead, set model.auth_mode: entra_id in config.yaml (or pick 'Microsoft Entra ID' in 'hermes model').r   )r   rZ   rU   r   r[  r   r   )r   r1   r>   r]   r2   r\   r   r   r   r   rG   r,   r   r   r   agent.azure_identity_adapterr_  r`  ra  ImportErrorr  rd  )r   r`   r/  r0  r   explicit_base_url_cleanrI   rH   cfg_api_modecfg_auth_mode	cfg_entra_entrar   r   r   env_base_urlrU   r   r   r[  r_  r`  ra  r   rc  entra_configtoken_providerclean_entraconfigured_scoperd  s                                 r+   _resolve_azure_foundry_runtimerr    s   4 +1r288:!"3"9r:@@BII#Ny}}Z06B7==?EEGLL%LM "I&9==4:;AACJJ3O&y}}Z'@AWEWIMM+6C)DJJLRRTaXaw'fd#I ,H)--	*BHbIOOQO<+??	F3ODH #L3R8>>@GGLL&F,F,H?
 	
 ++66)R2  
" ,GF!I  IMM'*0b1779 *) 32  "6\!J %GF"I
""9==#9#?R@FFH'7G$ ($ " "4	
 		
 G	7#$;<BG 126<<>7
 	
 -0AZF# 0 S  	H	\  ''*e1. 	   3C)s23:  	G	sT   K*  
K< ;L M *K98K9<	LLL	M &L;;M MMc           
        t        |xs d      j                         }t        |xs d      j                         j                  d      }|s|sy | dk(  rt        |j                  d      xs d      j                         j	                         }d}|dk(  rHt        |j                  d      xs d      j                         j                  d      }t        |      sd}|xs |xs d}|}|sddlm}	  |	       }|st        d	      dd
||d|dS | dk(  rn|xs t        }|}d }
|sTt               }|j                  dd      }|j                  d      }
|s%|j                  dd      j                  d      xs |}dd||d|
|dS | dk(  r]t        j                  d      xs i }|xsU t               xsI t        |j                  d      xs t        j                        j                         j                  d      }|xsN t        |t!        dt#        dd                  r,t        |j                  d      xs d      j                         nd}|j                  d      xs |j                  d      }|sit%        t'        t)        dd                  }|j                  dd      }|j                  d      }|s%|j                  dd      j                  d      xs |}dd||d||dS | dk(  rt+        ||||       S t-        j                  |       }|r<|j.                  dk(  r,d}|j0                  r3t)        |j0                  d      j                         j                  d      }|}|sA| d!v r-t3        |       }|j                  dd      j                  d      }n|xs |j4                  }|}|s@t3        |       }|j                  dd      }|s!|j                  dd      j                  d      }d}| d"k(  rt7        ||      }n6| d#k(  rd}n.t9        |j                  d$            }|r|}nt;        |      }|r|}| ||j                  d      |d|dS y )%Nr8   rO   r   r   rU   r   r   resolve_anthropic_tokenNo Anthropic credentials found. Set ANTHROPIC_TOKEN or ANTHROPIC_API_KEY, run 'claude setup-token', or authenticate with 'claude /login'.rR   rL  r;  r   r   last_refreshrP   r   rZ   rU   r   r   rw  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   rZ   rU   r   r   r~  r   r   )r   r`   r/  r0  >   kimi-codingkimi-coding-cnr   r   rZ   )r   r1   r>   r]   r2   r   agent.anthropic_adapterru  r   r   r   r   get_provider_auth_stater   DEFAULT_NOUS_INFERENCE_URLr   maxr%   r   floatr,   rr  r   	auth_typebase_url_env_varr   r   r   r\   rX   )r   r   r`   r/  r0  rI   rH   rU   r   ru  rw  credsstater~  r   env_urlrZ   ra   r   s                      r+   _resolve_explicit_runtimer  W  s    +1r288:-34::<CCCH$5;9==4:;AACIIK;&y}}Z8>B?EEGNNsSL2<@!$SS8S"G-/GV 
 $,  "4
 	
 >!$>(>"57Eii	2.G 99^4L$ 99Z4;;C@LH&)  ("4
 	
 6008>B o02o59912Yh6Y6YZ``biijmn 	 # 
#B A4HI 		+&,"-335
  	 YY56Q%))L:Q
4 %g.KT&R SE ii	2.G<0J$ 99Z4;;C@LH*  $"4
 	
 ?"-1-/	
 	
  ##H-G7$$	1##g66;AACJJ3OG$<<<XF 99Z4;;C@"@g&@&@"8BEii	2.G 99Z4;;C@%y 0GDH(H-immJ.GHO* 4H='H !  , "4
 	
 r-   )r   r/  r0  r   c           
     j  ? t        |       }ddlm}m}  |       }t	        |t
              r|j                  d      nd}t	        |t
              r;|j                  |      }	t	        |	t
              r ||	      st        d|d| d      |dk(  r	dd	d
dd|dS |xs dj                         }
|dk(  rhd|
v rd|xs dj                         xs6 t        dd      j                         xs t        dd      j                         }dd|
j                  d      |d|dS |dk(  rt        |t               |||      }|S |dv r7ddlm}  |       \  }}|r|st        d      dd	|j                  d      |d|dS t!        |||      }|r||d<   |S |s|st               }t#        |j                  d      xs d      j                         j%                         }t#        |j                  d      xs d      j                         ??r/|d v r+d!}t'        ?fd"|D              st)        |||      }||d<   |S t+        |||#      }t               }t-        |||||$      }|r|S |d%k7  }|d%k(  rt#        |j                  d      xs d      j                         j%                         }t#        |j                  d      xs d      j                         ?t        d&d      j                         }t        d'd      j                         }t/        |xs |xs |      }?r|d(v rd)}t/        |xs |      }|d*v xr | xr | }	 |rt1        |      nd}|rd|j5                         rS|j7                         }d}|t9        |d+d      xs t9        |d,d      }|d-k(  r|t;        d.t=        d/d0            }t9        |d1d      t9        |d2d      t9        |d3d      d4} t?        | |      st@        jC                  d5       	 |jE                         }!|!E|!}t9        |d+d      xs t9        |d,d      }t9        |d1d      t9        |d2d      t9        |d3d      d4} |rt?        | |      st@        jC                  d7       d}|?|r=tG        ||t9        |d8d      xs t9        |dd      xs d9      rtI        ||||||:      S |d-k(  rx	 tK        tM        t        d;d<            =      }#d-d	|#j                  dd      j                  d      |#j                  d>d      |#j                  d?d@      |#j                  dA      |dBS |dEk(  rc	 tQ               }#dEdF|#j                  dd      j                  d      |#j                  d>d      |#j                  d?dG      |#j                  dH      |dIS |dKk(  rn	 tS               }#dKdF|#j                  d      xs dj                  d      xs tT        |#j                  d>d      |#j                  d?dG      |#j                  dH      |dIS |dMk(  rc	 tW               }#dMd	|#j                  dd      j                  d      |#j                  d>d      |#j                  d?dN      |#j                  dO      |dPS |dRk(  rRtY        j                  |      }$|$r;|$jZ                  dSk(  r,ddTl.m/}%  |%       }#|d|#d   |#d>   |#j                  d?dU      |dS |dVk(  rta        |      }#dVd	|#j                  dd      j                  d      |#j                  d>d      |#j                  dWd      tc        |#j                  dX      xs g       |#j                  d?dY      |dZS |dk(  rt#        |j                  d      xs d      j                         j%                         }d?|dk(  r?|j                  d      xs dj                         j                  d      ?te        ?      sd??xs d[}d|j%                         v xs ?xr d?j%                         v }&|&rd}d\D ]O  }'t#        |j                  |'      xs d      j                         }(|(s2t        |(d      j                         }|sO n |s,t#        |j                  d>      xs d      j                         }|s6t        dd      j                         xs t        dd      j                         }|s%t        d]      dd^l3m4})  |)       }|st        d_      dd||d`|dS |dak(  rddbl5m6}*m7}+m8},m9}- |dcv }.|.s |*       st        dddef       |       j                  dai       }/|/j                  dg      xs dj                         xs  |,       }0 |+       xs dh}1|/j                  dii       }2d}3|2j                  dj      rN|2j                  dk      r=|2dj   |2dk   dl}3|2j                  dm      r|2dm   |3dn<   |2j                  do      r|2do   |3do<   t#        |xs |j                  dp      xs d      j                         }4t/        tt        jv                  j                  dqd      j                               }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'|$jZ                  d>k(  rty        |      }#t{        |#j                  d>            s9dyj}                  |$j~                        }6|6rdz|6 d{nd}7t        d|| d}|7 |d~      t#        |j                  d      xs d      j                         j%                         }d?||k(  r2|j                  d      xs dj                         j                  d      ??xs! |#j                  dd      j                  d      }d	}8|dk(  rt        ||#j                  d>d            }8n|dk(  rdF}8nt#        |j                  d      xs d      j                         j%                         }9t        |j                  d            }:|dv r&ddlBmC}; |xs |j                  dpd      }< |;||<      }8n |:rt        ||9      r|:}8nt        |      }=|=r|=}8|dv rddlBmF}>  |>||8|      }|dk(  rt        j                  |      }||8||#j                  d>d      |#j                  d?d`      |dS t)        |||      }||d<   |S # t2        $ r d}Y 	w xY w# t2        $ r#}"t@        jC                  d6|"       d}!Y d}"~"	 d}"~"ww xY w# t        $ r |dCk7  r t@        jO                  dD       Y w xY w# t        $ r |dCk7  r t@        jO                  dJ       Y w xY w# t        $ r |dCk7  r t@        jO                  dL       Y w xY w# t        $ r |dCk7  r t@        jO                  dQ       Y Cw xY w)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)moar[   zmoa://localzmoa-virtual-providerr;  r8   r   z	azure.comAZURE_ANTHROPIC_KEYANTHROPIC_API_KEYrR   rO   zazure-explicitr   )r   r`   r/  r0  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. Install the extra with: pip install 'hermes-agent[vertex]'.r  zvertex-oauth)r   r/  r0  r   r   rU   )r   r8   )rE   zanthropic.comr2  c              3  6   K   | ]  }t        |        y wrf   )r#   )ri   r?   rH   s     r+   rk   z+resolve_runtime_provider.<locals>.<genexpr>  s        &lD9s   r.  )r   r   r`   r/  r0  r   OPENAI_BASE_URLr"   >   r   rC   T>   r   r   r   r   r   ry  rz  r{  r|  r}  rc  )r|  r}  rc  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   )rU   )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   rP   zhermes-auth-storerw  rx  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   rZ   rU   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   rZ   rU   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.rt  rv  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   rZ   rU   r   r   r  bedrock_anthropicr   r   )r   rZ   rU   r   r   r  r   guardrail_configz, z Set r9   z*No usable credentials found for provider 'z'.missing_api_key)r   r  r   r   rZ   r   r   r   r   )Ir   r  r  r    r   r   r]   
ValueErrorr1   r,   r>   rr  r   agent.vertex_adapterr  r   rG  r   r2   ry   rY  r   r  boolr   rG   r   r   r   r  r%   r   r^   r   try_refresh_currentr   r   r   r  r_   r   r   r   r   r   r  rF   r  r   listr   r  ru  agent.bedrock_adapterr  r  r  r  r%  r&  r   r   r}   api_key_env_varsr   r\   r   r   r   rX   r   r   r   )@r   r/  r0  r   r   r  r    	_full_cfg
_provs_cfg_block	_eff_base
_azure_keyazure_runtimer  tokenrU   custom_runtimer`   rI   _known_cloud_hostsr   r   explicit_runtimeshould_use_poolenv_openai_base_urlrP  has_custom_endpointhas_runtime_overrider   r   r   min_ttl
nous_state	refreshedr   r  r   r  _is_azure_endpointhint_keyenv_varru  r  r  r  r  is_explicit_bedrock_cfgr  auth_source_grr  _current_model_has_bearer_token	env_nameshintrZ   r   ra   r   
_effectiver   r   rH   s@                                                                  @r+   resolve_runtime_providerr    s   " 4I> CI/9)T/J{+PTJ*d# 23fd#,?,G.1 2011AC 
 U"*%-,"4
 	
 #(b//1I[([I-E#**, 8,b17798*B/557 	 $,!((-!&"4
 	
 _,61')-/%
  __:+-xHN  !* ,$"4
 	
 3-)+N
 /A+, %5%'	9==4:;AACIIK9==4:;AACLL8"
  .  6'9%5&7
 1C,-)+H
 "#I0-)+ ,.O<9==4:;AACIIK9==4:;AAC%&7<BBD")*?"D"J"J"L" '"'&

 L,>>"&#$4$I8IJ"88 )'')(( 	&5y"4 $$&0$7 65."5  v%"3"g&GNOG$UK>(/7Mt(T 6J
 (
G<hi% $ 8 8 :I (%E'8$? >"5."= !
 &-UK%F07?UW[0\!(!>"J
 $+?
G+TLL!uv#%L0E#5t< uj$7 4!#5#)  6	=4 %g.KT&R SE #.!IIj"5<<SA 99Y3))Hh7#ii5&8 " >!	=57E*-!IIj"5<<SA 99Y3))H.AB %		. 9&8 " ;	=9;E'-"YYz28b@@EcIc 99Y3))H.AB %		. 9&8  <	=46E(.!IIj"5<<SA 99Y3))Hj9!&?!;&8  ?"#''1w((O;Q=?E$0!*- +))Hg6&8  = =hG%*		*b188=yyB/yyB/6*0b1ii)4"4	
 		
 ; 9==4:;AACIIK;&%MM*5;BBDKKCPL2<@!>#> )HNN,<< 
@[L,>,>,@@ 	  E6 immH5;<BBD#GR0668E IMM)4:;AAC126<<> @2B7==?  E  H+-EV 
 $, "4
 	
 9	
 	
 ),ii#6#8@
 *  #}((B7""8,299;W?U?W.0K4K{B/77)*sww7J/K'*+A'B$'(;$<  ww/0;>?W;X !78www,/L ) \KY]]9-EKLRRT 0JB!O!U!U!WX%n5>O &06vhnM$% %)&8	G &.6vhnM$% &8G *:G&'  ##H-G7$$	14X> !9!56		'":":;I+4U9+Q'"D<XJbO!&  9==4:;AACIIK8#%MM*5;BBDKKCPLH599Z#<#C#CC#H%y 0EIIiQS<TUH(H"%immJ&?&E2"F"L"L"N"T"T"V-immJ.GHO:: F)IY]]9b-I
28ZH %I(Tg%h*
 4H='H66E28XxPHz!DDXNH   yyB/ii%0"4
 	
 *-)+G
 %7G !NW  6 ! %LL!EsK $I%j  	=!V+ KK < =	=(  	=!V+ KK < =	=(  	=!V+KK < =	=$  	=!V+KK < =	=sv   8s 1s 4A6t	 1A!t4 A,u A!v
 ss	t#tt	$t10t14$uu$vv
$v21v2c                N    t        | t              rt        |       S t        |       S rf   )r   r   r   r   )errors    r+   format_runtime_provider_errorr  J  s!    %# ''u:r-   )r8   )r(   r   r)   r   returnr   )r5   r   r  r   )r?   r   r  r  )rH   r   rI   r   r  r  )rU   r   r  Optional[str])r`   Dict[str, Any]rU   r   r  r   )rU   r   r  r   )rU   r   r  r  )r  r  rf   )r   r  r   r  r  r  )r`   r  r   r   r  r   )r   r   r  r  )r  r   )r   r   rZ   r   r`   Optional[Dict[str, Any]]r  r   )r   r   r   r
   r   r   r`   r  r   zOptional[CredentialPool]r   r  r  r  )r   r  r  r   )NN)
rU   r   r   r   r   r  r   r  r  r  )r   r  r   r  r  None)r   r   r  r  )r   r   r  r  )rU   r  r#  r  r  r  )r,  r  r  r  )r   r   r/  r  r0  r  r  r  )r   r   r/  r  r0  r  r  r  )r   r   r`   r  r/  r  r0  r  r   r  r  r  )r   r   r   r   r`   r  r/  r  r0  r  r  r  )
r   r  r/  r  r0  r  r   r  r  r  )r  rG   r  r   )W__doc__
__future__r   loggingr%  r   urllib.parser   typingr   r   r   	getLogger__name__r^   
hermes_clir   r   agent.credential_poolr	   r
   r   r   r   agent.secret_scoper   r'   rF   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,   r6   rA   rM   rX   rc   r   r   r   r   r   r   r   r\   r   r   r   r   r   r  r  r  r  r"  r)  r  r-  rG  rY  rr  r  r  r  r   r-   r+   <module>r     s<   M "  	 	 ! & &			8	$ '  9    $ 
 1 C C
/3=
5<&RB,61r"J.,8""$ 0  (	
 	> +/%)"&LL L 	L
 (L #L  L L^, (,#'	 % !	
 @0dN0j #%)<< #< 	<~8, '+'+	AA $A %	A
 AN '+'+	KK $K %	K
 Kd '+'+"&ff f $	f
 %f  f f\ '+'+XX X 	X
 $X %X Xz  $&*'+"&U	U	 $U	 %	U	
  U	 U	pr-   