Ë
    âß²j
à ã                  ó\  — U d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlmZmZ ddlmZmZ ddlmZ ddl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 dd
l m!Z! ddl"m#Z#m$Z$m%Z% ddl&m'Z' ddl(m)Z)m*Z*m+Z+m,Z, ddl-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3 ddl4m5Z5m6Z6 ddl7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z>m?Z?m@Z@mAZAmBZBmCZCmDZDmEZE ddlFmGZGmHZHmIZImJZJmKZKmLZL ddlMmNZNmOZOmPZPmQZQmRZRmSZSmTZTmUZUmVZVmWZWmXZXmYZYmZZZm[Z[m\Z\m]Z]m^Z^m_Z_m`Z`maZambZbmcZcmdZdmeZemfZfmgZgmhZhmiZimjZjmkZkmlZlmmZmmnZnmoZompZpmqZqmrZrmsZsmtZt ddlumvZvmwZwmxZxmyZymzZzm{Z{m|Z|m}Z}m~Z~mZm€Z€m�Z�m‚Z‚ ddlƒm„Z„m…Z…m†Z†m‡Z‡mˆZˆm‰Z‰mŠZŠm‹Z‹mŒZŒm�Z�mŽZŽm�Z�m�Z�m‘Z‘ 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¢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² 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Ã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Ó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â  e�jÆ                  eä«      Zå	 ddlæZæ	 ddlèZè�d§d„Zé�d¨d„Zêe G d„ d«      «       Zë	 �d©	 	 	 	 	 	 	 	 	 	 	 	 	 �dªd„Zìg  eëdd d!e·e¸e¹e»¬"«      ‘ eëd#d$d%eÀ¬&«      ‘d'‘ eëd(d)d%eÁ¬&«      ‘ eëd*d+d%eÉ¬&«      ‘d,‘d-d.eÊd/d0f‘ eëd1d2d3eËd4¬5«      ‘d6‘d7‘d8‘d9‘d:d;eÏd<d=f‘d>‘d?‘d@dAeÍdBdCf‘dD‘ eëdEdFdGeÄeÆeÂeÃdHeÅeÇdIœ¬J«      ‘dK‘dL‘dM‘dN‘dO‘dP‘dQ‘dR‘dS‘dT‘dU‘dV‘dW‘dX‘dY‘dZd[eÌd\d]f‘d^‘d_‘d`‘­Zídaeîdb<   dc„ eíD «       D � ci c]  } | �jÞ                  | “Œ c} Zðddeîde<    eñeð«      ZòddflómôZômõZõmöZöm÷Z÷møZø ddglùmúZúmûZümýZý  eý«        �d«dh„Zþh di£Zÿdj�Z �d¬dk„�Zdldmœ�d­dn„�Zdodpi�Zdqeîdr<   �d®ds„�Z�d¯dt„�Z�d°du„�Z�d±dv„�Z�d²dw„�Zdxdydzœ�Z	 eñ�e	«      h d{£z  �Z
�d³d|„�Z�d´d}„�Z�dµd~„�Z�d¶d„�Z�d·d€„�Zi �Zd�eîd‚<    e�j"                  «       �Z�d¸dƒ„�Z�d¸d„„�Z�d¹d…„�Z�dºd†„�Z�d»d‡„�Ze	 	 	 	 	 	 	 	 �d¼dˆ„«       �Zee¶fdd‰œ	 	 	 �d½dŠ„«       �Z�d·d‹„�Z�d¾�d¿dŒ„�Zd�dŽœ�dÀd�„�Z�d¾�dÁd�„�Z�dÂd‘„�Z�dÃd’„�Z	 	 	 	 	 	 �dÄd“„�Z �dÅd”„�Z!ee¶f	 	 	 �dÆd•„«       �Z"d–d—œ	 	 	 	 	 	 	 	 	 �dÇd˜„�Z#�dÈd™„�Z$�dÉdš„�Z%d�d—œ	 	 	 	 	 	 	 	 	 �dÊd›„�Z&	 	 	 	 	 	 	 	 	 	 �dËdœ„�Z'�dÌd�„�Z(�dÍdž„�Z)�d¯dŸ„�Z*�dÍd „�Z+�d¾�dÎd¡„�Z,d¢�Z-	 	 	 	 	 	 	 	 �dÏd£„�Z.�dÐd¤„�Z/ddd¥œ	 	 	 	 	 	 	 	 	 �dÑd¦„�Z0�dÒd§„�Z1�dÓd¨„�Z2�dÔd©„�Z3�dÔdª„�Z4�dÕd«„�Z5�dÖd¬„�Z6�d×d­„�Z7�dØd®„�Z8�dÙd¯„�Z9�dØd°„�Z:�dØd±„�Z; eñd²h«      �Z< eñh d³£«      �Z=d´�Z>�dÚdµ„�Z?�dØd¶„�Z@�dÛd·„�ZA�dØd¸„�ZB�e8d–f�e:d–f�e@d�f�e;d–f�eBd–ff�ZCd¹eîdº<   �dÍd»„�ZD�d¾�dÜd¼„�ZE�dÝd½„�ZF�dÞd¾„�ZG�dÝd¿„�ZHi dÀdÁ“dÂdÁ“dÃdÁ“dÄdÁ“dÅdÆ“dÇdÆ“dÈdÆ“dÉdÊ“dËdÊ“dÌdÊ“d(d(“dÍd(“dÎd(“dÏd(“dÐdÑ“dÒdÑ“dÓdÑ“i dÔdÕ“dÖdÕ“d×d:“dØd:“dÙdÚ“dÛdÚ“dÜdÝ“dÞdÝ“dßd@“dàd@“dád@“dâdã“dädã“dådE“dædE“dçdE“dèdé“¥i dêdé“dëdé“dìdí“dîdí“dïd-“dðd-“dñd-“dòd-“dód1“dôd1“dõdö“d÷dö“dødö“dùdú“dûdú“düd*“dýd*“¥i d*d*“dþdÿ“�d dÿ“�ddÿ“�d�d“�d�d“�d�d“�d�d“�d�d“�d	�d“�d
�d“�d�d“�d�d“�d�d“�d�d“�d�d“�d�d“¥�d�d�d�d�d�d�dd#d#�ddZ�d�d�d�d�dœ¥�ZI�deî�d<   �dß�d„�ZJ�dà�d„�ZK�dá�d„�ZLd��dœ�dâ�d„�ZM�dã�d„�ZN eñd-�dh«      �ZO	 	 	 	 	 	 �dä�d „�ZP	 �d¾ddd��d!œ	 	 	 	 	 	 	 	 	 �då�d"„�ZQ�d«�d#„�ZR�dæ�d$„�ZS�dç�d%„�ZT�dè�d&„�ZUd�d'œ	 	 	 	 	 	 	 	 	 �dé�d(„�ZV�d)�ZW�dê�d*„�ZX�dë�d+„�ZY�dì�d,„�ZZ eñh �d-£«      �Z[�d.eî�d/<    e�j"                  «       �Z\i �Z]�d0eî�d1<   �d2�Z^�dí�d3„�Z_�d4dde¾�d5œ	 	 	 	 	 	 	 	 	 �dî�d6„�Z`�d4�Zad�ab�d7eî�d8<   d�ac�d9eî�d:<   �dï�d;„�Zd�dÝ�d<„�Ze�d·�d=„�Zf ed–�¬>«       G �d?„ �d@«      «       �Zg eñh �dA£«      �Zh eñh �dB£«      �Zi �egd�dC�dD�eh�eiz  d–�¬E«       �egd#�dF�dG�eh�dH�dIhz  d–�¬E«       �egd(�dJ�dK eñ�dL�dMh«      d–�¬E«       �egd*�dN�dO«       �egdE�dP�dQ«      �dRœ�Zj�dSeî�dT<   �dð�dU„�Zk e�ekd�¬V«      �Zl e�ekd(�¬V«      �Zm e�ekd#�¬V«      �Zn�dñ�dW„�Zo�d·�dX„�Zp�d·�dY„�Zq�dò�dZ„�Zr�dó�d[„�Zs�dô�d\„�Zt�dõ�d]„�Zu	 	 	 	 �dö�d^„�Zv�dó�d_„�Zw�d÷�d`„�Zx�d¾�dÎ�da„�Zyi �ej�jõ                  «       D ��ci c]  \  }}||�jö                  “Œ c}}¥�db�dc�ddœ¥�Z|�deî�de<   �df�dg�dh�di�di�djœ�Z}�deî�dk<   �d·�dl„�Z~�dø�dm„�Z�dø�dn„�Z€e1e1e2�e€�do„ �dp„ �dqœ�Z��dreî�ds<   �dó�dt„�Z‚�dó�du„�Zƒ	 �d¾d��dvœ	 	 	 	 	 	 	 	 	 �dù�dw„�Z„�d×�dx„�Z…�dÜ�dy„�Z†�d×�dz„�Z‡�dµ�d{„�Zˆ�dÝ�d|„�Z‰�d·�d}„�ZŠ�dÝ�d~„�Z‹d�d�lŒ�m��Z� d�d€�lŒ�mŽ�ZŽ d�d�l�m��Z� dd�l��Z�dd�l‘�Z‘d�d‚l �m’�Z’ dd�l“�Z“dd�l”�Z”dd�l•�Z•d�dƒl �m–�Z– i �d„�d…“�d†�d‡“�dˆ�d‰“�dŠ�d‹“�dŒ�d�“�dŽ�d�“�d��d‘“�d’�d““�d”�d•“�d–�d—“�d˜�d™“�dš�d›“�dœ�d�“�dž�dŸ“�d �d¡“�d¢�d£“�d¤�d¥“�Z—�d¦„ �Z˜y# eç$ r dZæY �Œqw xY w# eç$ r dZèY �Œzw xY wc c} w c c}}w (ú  a  Multi-provider authentication system for Hermes Agent.

- ``ProviderConfig`` / ``PROVIDER_REGISTRY`` describe every known inference provider.
- The auth store (``~/.hermes/auth.json``) holds per-provider state, the credential pool and
  suppression markers; ``_auth_store_lock`` / ``_load_auth_store`` / ``_save_auth_store`` are the
  only I/O primitives (cross-process flock, atomic 0o600 writes).
- ``resolve_provider()`` picks the active provider via the documented priority chain.
- ``OAUTH_PROVIDER_FLOWS`` maps each OAuth provider to its resolver/status builder; the flows live in
  ``auth_nous``/``auth_codex``/``auth_xai``/``auth_qwen``/``auth_minimax``/``auth_spotify``/``auth_openrouter`` and are
  re-imported here so ``hermes_cli.auth.<name>`` stays the public/patchable surface.é    )ÚannotationsN)Ú	ExitStackÚcontextmanager)Ú	dataclassÚfield)Úpartial)ÚdatetimeÚtimezone)ÚPath)ÚAnyÚCallableÚDictÚ	FrozenSetÚIterableÚListÚOptionalÚTuple)Úurlparse)ÚOPENROUTER_BASE_URLÚhermes_home_keyÚsecure_parent_dir)Ú$sanitize_borrowed_credential_payload)Úatomic_json_writeÚ	env_floatÚfile_signatureÚis_truthy_value)ÚKIMI_CODE_BASE_URLÚZAI_ENDPOINTSÚ$_normalize_lmstudio_runtime_base_urlÚ_resolve_kimi_base_urlÚ_resolve_zai_base_urlÚdetect_zai_endpoint)Ú_prompt_model_selectionÚ_save_model_choice)Ú_can_open_graphical_browserÚ_default_verifyÚ_is_remote_sessionÚ!_nous_device_auth_timeout_messageÚ!_offer_existing_oauth_credentialsÚ_poll_device_token_genericÚ_poll_for_tokenÚ_print_device_code_instructionsÚ_print_login_successÚ_print_loopback_ssh_hintÚ_prompt_yes_noÚ_request_device_codeÚ_resolve_verifyÚ_ssh_user_at_host)Ú!SINGLE_USE_REFRESH_POOL_PROVIDERSÚ_oauth_heal_clean_marksÚ_oauth_heal_noticesÚconsume_oauth_heal_noticesÚ#heal_forked_single_use_oauth_grantsÚ$strip_cloned_single_use_oauth_grants)'ÚNOUS_SESSION_TERMINALÚNOUS_SESSION_UNKNOWNÚNOUS_SESSION_VALIDÚ_ALLOWED_NOUS_INFERENCE_HOSTSÚ_agent_key_is_usableÚ_apply_nous_refreshed_tokensÚ!_assert_nous_inference_jwt_usableÚ_compute_nous_auth_statusÚ#_format_nous_entitlement_auth_errorÚ_healed_nous_inference_urlÚ_login_nousÚ_merge_shared_nous_oauth_stateÚ_migrate_stale_nous_portal_urlÚ_nous_device_code_loginÚ_nous_inference_env_overrideÚ_nous_invoke_jwt_is_usableÚ_nous_invoke_jwt_statusÚ_nous_portal_env_overrideÚ_nous_shared_store_lockÚ_nous_shared_store_pathÚ_pool_first_oauth_statusÚ_quarantine_nous_oauth_stateÚ_quarantine_nous_pool_entriesÚ_read_shared_nous_stateÚ_refresh_access_tokenÚ_refresh_nous_or_quarantineÚ_select_nous_invoke_jwtÚ_sync_nous_pool_from_auth_storeÚ_token_fingerprintÚ_try_import_shared_nous_stateÚ)_validate_nous_inference_url_from_networkÚ_write_shared_nous_stateÚfetch_nous_modelsÚget_nous_auth_status_localÚget_nous_session_validityÚpersist_nous_credentialsÚrefresh_nous_oauth_from_stateÚ resolve_nous_runtime_credentialsÚstep_up_nous_billing_scope)Ú_MINIMAX_OAUTH_ERROR_BODY_LIMITÚ_login_minimax_oauthÚ_minimax_oauth_loginÚ_minimax_pkce_pairÚ_minimax_poll_tokenÚ_minimax_post_formÚ_minimax_request_user_codeÚ"_minimax_resolve_token_expiry_unixÚ_minimax_response_error_textÚ_minimax_save_auth_stateÚ_refresh_minimax_oauth_stateÚ"build_minimax_oauth_token_providerÚ)resolve_minimax_oauth_runtime_credentials)Ú_login_xai_oauthÚ_read_xai_oauth_tokensÚ_refresh_xai_oauth_tokensÚ_save_xai_oauth_tokensÚ'_write_through_xai_oauth_to_global_rootÚ_xai_access_token_is_expiringÚ_xai_oauth_device_code_loginÚ_xai_oauth_discoveryÚ_xai_oauth_poll_device_tokenÚ_xai_oauth_request_device_codeÚ#_xai_proactive_refresh_skew_secondsÚ _xai_validate_inference_base_urlÚrefresh_xai_oauth_pureÚ%resolve_xai_oauth_runtime_credentials)Ú_codex_access_token_is_expiringÚ_codex_device_code_loginÚ_codex_http_clientÚ_codex_pool_rate_limit_statusÚ_codex_quota_probe_cacheÚ_codex_usage_probe_urlÚ_import_codex_cli_tokensÚ_is_codex_rate_limit_shapedÚ_login_openai_codexÚ_probe_codex_quota_restoredÚ_read_codex_tokensÚ_refresh_codex_auth_tokensÚ"_refresh_expired_codex_probe_tokenÚ_save_codex_tokensÚ clear_codex_pool_quota_cooldownsÚrefresh_codex_oauth_pureÚ!resolve_codex_runtime_credentials)Ú_refresh_spotify_oauth_stateÚget_spotify_auth_statusÚlogin_spotify_commandÚ#resolve_spotify_runtime_credentials)Ú_openrouter_pkce_login)Ú_qwen_access_token_is_expiringÚ_qwen_cli_auth_pathÚ_read_qwen_cli_tokensÚ_refresh_qwen_cli_tokensÚ_save_qwen_cli_tokensÚget_qwen_auth_statusÚ resolve_qwen_runtime_credentials)/Ú_decode_jwt_claimsÚAUTH_STORE_VERSIONÚAUTH_LOCK_TIMEOUT_SECONDSÚDEFAULT_NOUS_PORTAL_URLÚDEFAULT_NOUS_INFERENCE_URLÚDEFAULT_NOUS_CLIENT_IDÚNOUS_BILLING_MANAGE_SCOPEÚDEFAULT_NOUS_SCOPEÚNOUS_DEVICE_CODE_SOURCEÚNOUS_AUTH_PATH_INVOKE_JWTÚ!ACCESS_TOKEN_REFRESH_SKEW_SECONDSÚNOUS_INVOKE_JWT_MIN_TTL_SECONDSÚDEFAULT_CODEX_BASE_URLÚDEFAULT_XAI_OAUTH_BASE_URLÚMINIMAX_OAUTH_CLIENT_IDÚMINIMAX_OAUTH_SCOPEÚMINIMAX_OAUTH_GLOBAL_BASEÚMINIMAX_OAUTH_CN_BASEÚMINIMAX_OAUTH_GLOBAL_INFERENCEÚMINIMAX_OAUTH_CN_INFERENCEÚ"MINIMAX_OAUTH_REFRESH_SKEW_SECONDSÚDEFAULT_QWEN_BASE_URLÚDEFAULT_GITHUB_MODELS_BASE_URLÚDEFAULT_COPILOT_ACP_BASE_URLÚDEFAULT_OLLAMA_CLOUD_BASE_URLÚDEFAULT_ACTUAL_BASE_URLÚDEFAULT_ACTUAL_LOCAL_BASE_URLÚSTEPFUN_STEP_PLAN_INTL_BASE_URLÚSTEPFUN_STEP_PLAN_CN_BASE_URLÚCODEX_OAUTH_CLIENT_IDÚCODEX_OAUTH_TOKEN_URLÚ'CODEX_ACCESS_TOKEN_REFRESH_SKEW_SECONDSÚXAI_OAUTH_CLIENT_IDÚXAI_OAUTH_SCOPEÚ%XAI_ACCESS_TOKEN_REFRESH_SKEW_SECONDSÚ&QWEN_ACCESS_TOKEN_REFRESH_SKEW_SECONDSÚ!DEFAULT_SPOTIFY_ACCOUNTS_BASE_URLÚDEFAULT_SPOTIFY_API_BASE_URLÚSPOTIFY_DOCS_URLÚDEFAULT_SPOTIFY_SCOPEÚSERVICE_PROVIDER_NAMESÚLMSTUDIO_NOAUTH_PLACEHOLDERÚACTUAL_LOCAL_NOAUTH_PLACEHOLDERÚCODEX_RATE_LIMITED_CODEÚ	AuthErrorÚ	_nous_errÚhttpxc                óž   — 	 t        | xs d«      j                  xs dj                  «       j                  d«      }|dv S # t        $ r Y yw xY w)z5Return True for Actual's loopback local API endpoint.Ú ú.F>   ú::1ú0.0.0.0Ú	localhostú	127.0.0.1)r   ÚhostnameÚlowerÚrstripÚ	Exception)Úbase_urlÚhosts     ú4/home/ubuntu/.hermes/hermes-agent/hermes_cli/auth.pyÚis_actual_local_base_urlrÕ   v   sV   € ðÜ˜š RÓ(×1Ñ1Ò7°R×>Ñ>Ó@×GÑGÈÓLˆð Ð?Ð?Ð?øô ò Ùðús   ‚:A  Á 	AÁAc                ój  — t        | xs d«      j                  «       j                  d«      }|st        S 	 t	        |«      }|j
                  xs dj                  «       j                  d«      }|j                  j                  d«      }|dv r|dk(  st        |«      r|dz   S |S # t        $ r |cY S w xY w)z¬Return Actual's OpenAI-compatible base URL (hosted api.actual.inc or the loopback local server;
    both expose a /v1 surface for the selected OpenAI-compatible transport).rÈ   ú/rÉ   >   rÈ   r×   zapi.actual.incz/v1)
ÚstrÚstriprÐ   r±   r   rÎ   rÏ   ÚpathrÑ   rÕ   )rÒ   ÚurlÚparsedrÓ   rÚ   s        rÔ   Únormalize_actual_base_urlrÝ      s³   € ô ˆhŠn˜"Ó
×
#Ñ
#Ó
%×
,Ñ
,¨SÓ
1€CÙÜ&Ð&ðÜ˜#“ˆØ—‘Ò% 2×,Ñ,Ó.×5Ñ5°cÓ:ˆØ�{‰{×!Ñ! #Ó&ˆð ˆyÑ˜dÐ&6Ò6Ô:RÐSVÔ:WØ�U‰{ÐØ€Jøô	 ò ØŠ
ðús   ¶AB$ Â$B2Â1B2c                  ó    — e Zd ZU dZded<   ded<   ded<   dZded<   dZded<   dZded	<   dZded
<    e	e
¬«      Zded<   dZded<   dZded<   y)ÚProviderConfigz%Describes a known inference provider.rØ   ÚidÚnameÚ	auth_typerÈ   Úportal_base_urlÚinference_base_urlÚ	client_idÚscope)Údefault_factoryúDict[str, Any]Úextra© ÚtupleÚapi_key_env_varsÚbase_url_env_varN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú__annotations__rã   rä   rå   ræ   r   Údictré   rì   rí   rê   ó    rÔ   rß   rß   ’   sa   … á/ØƒGØ
ƒIØƒNØ€O�SÓØ Ð˜Ó Ø€IˆsÓØ€Eˆ3ƒOÙ!°$Ô7€Eˆ>Ó7Ø Ð�eÓ ØÐ�cÔrô   rß   c                ó$   — t        | |||||¬«      S )z@Compact constructor for the common env-var-keyed provider shape.)rà   rá   râ   rä   rì   rí   )rß   )rà   rá   rä   rì   rí   râ   s         rÔ   Ú_api_key_providerrö   ¡   s#   € ô Ø�D IÐBTØ)Ð<LôNð Nrô   ÚnouszNous PortalÚoauth_device_code)rã   rä   rå   ræ   úopenai-codexzOpenAI CodexÚoauth_external)rä   )z
openai-apiz
OpenAI APIzhttps://api.openai.com/v1)ÚOPENAI_API_KEYÚOPENAI_BASE_URLú	xai-oauthz%xAI Grok OAuth (SuperGrok / Premium+)ú
qwen-oauthz
Qwen OAuth)Úlmstudioz	LM Studiozhttp://127.0.0.1:1234/v1)Ú
LM_API_KEYÚLM_BASE_URLÚcopilotzGitHub Copilot)ÚCOPILOT_GITHUB_TOKENÚGH_TOKENÚGITHUB_TOKENÚCOPILOT_API_BASE_URLúcopilot-acpzGitHub Copilot ACPÚexternal_processÚCOPILOT_ACP_BASE_URL)rä   rí   )ÚgeminizGoogle AI Studioz0https://generativelanguage.googleapis.com/v1beta)ÚGOOGLE_API_KEYÚGEMINI_API_KEYÚGEMINI_BASE_URL)Úzaiz
Z.AI / GLMzhttps://api.z.ai/api/paas/v4)ÚGLM_API_KEYÚZAI_API_KEYÚZ_AI_API_KEYÚGLM_BASE_URL)úkimi-codingzKimi / Moonshotzhttps://api.moonshot.ai/v1)ÚKIMI_API_KEYÚKIMI_CODING_API_KEYÚKIMI_BASE_URL)úkimi-coding-cnzKimi / Moonshot (China)zhttps://api.moonshot.cn/v1)ÚKIMI_CN_API_KEYÚstepfunzStepFun Step Plan)ÚSTEPFUN_API_KEYÚSTEPFUN_BASE_URL)ÚarceezArcee AIzhttps://api.arcee.ai/api/v1)ÚARCEEAI_API_KEYÚARCEE_BASE_URL)Úgmiz	GMI Cloudzhttps://api.gmi-serving.com/v1)ÚGMI_API_KEYÚGMI_BASE_URLÚactualzActual Computer)ÚACTUAL_API_KEYÚACTUAL_BASE_URL)ÚminimaxÚMiniMaxz https://api.minimax.io/anthropic)ÚMINIMAX_API_KEYÚMINIMAX_BASE_URLúminimax-oauthu   MiniMax (OAuth Â· minimax.io)Úoauth_minimaxÚglobal)ÚregionÚcn_portal_base_urlÚcn_inference_base_url)rã   rä   rå   ræ   ré   )Ú	anthropicÚ	Anthropiczhttps://api.anthropic.com)ÚANTHROPIC_API_KEYÚANTHROPIC_TOKENÚCLAUDE_CODE_OAUTH_TOKENÚANTHROPIC_BASE_URL)Úalibabaz
Qwen Cloudz6https://dashscope-intl.aliyuncs.com/compatible-mode/v1)ÚDASHSCOPE_API_KEYÚDASHSCOPE_BASE_URL)úalibaba-coding-planzAlibaba Cloud (Coding Plan)z-https://coding-intl.dashscope.aliyuncs.com/v1)ÚALIBABA_CODING_PLAN_API_KEYr6  ÚALIBABA_CODING_PLAN_BASE_URL)ú
minimax-cnzMiniMax (China)z"https://api.minimaxi.com/anthropic)ÚMINIMAX_CN_API_KEYÚMINIMAX_CN_BASE_URL)ÚdeepseekÚDeepSeekzhttps://api.deepseek.com/v1)ÚDEEPSEEK_API_KEYÚDEEPSEEK_BASE_URL)ÚxaiÚxAIzhttps://api.x.ai/v1)ÚXAI_API_KEYÚXAI_BASE_URL)Únvidiaz
NVIDIA NIMz#https://integrate.api.nvidia.com/v1)ÚNVIDIA_API_KEYÚNVIDIA_BASE_URL)ú
ai-gatewayzVercel AI Gatewayzhttps://ai-gateway.vercel.sh/v1)ÚAI_GATEWAY_API_KEYÚAI_GATEWAY_BASE_URL)úopencode-zenzOpenCode Zenzhttps://opencode.ai/zen/v1)ÚOPENCODE_ZEN_API_KEYÚOPENCODE_ZEN_BASE_URL)úopencode-gozOpenCode Gozhttps://opencode.ai/zen/go/v1)ÚOPENCODE_GO_API_KEYÚOPENCODE_GO_BASE_URL)Úkilocodez	Kilo Codezhttps://api.kilo.ai/api/gateway)ÚKILOCODE_API_KEYÚKILOCODE_BASE_URL)ÚhuggingfacezHugging Facez https://router.huggingface.co/v1)ÚHF_TOKENÚHF_BASE_URL)ÚxiaomizXiaomi MiMozhttps://api.xiaomimimo.com/v1)ÚXIAOMI_API_KEYÚXIAOMI_BASE_URL)útencent-tokenhubzTencent TokenHubz#https://tokenhub.tencentmaas.com/v1)ÚTOKENHUB_API_KEYÚTOKENHUB_BASE_URL)útencent-tokenplanzTencent TokenPlanz2https://api.lkeap.cloud.tencent.com/plan/anthropic)ÚTOKENPLAN_API_KEYÚTOKENPLAN_BASE_URLzollama-cloudzOllama Cloud)ÚOLLAMA_API_KEYÚOLLAMA_BASE_URL)ÚbedrockzAWS Bedrockz/https://bedrock-runtime.us-east-1.amazonaws.comrê   ÚBEDROCK_BASE_URLÚaws_sdk)ÚvertexzGoogle Vertex AIrÈ   rê   rÈ   rf  )úazure-foundryzAzure FoundryrÈ   )ÚAZURE_FOUNDRY_API_KEYÚAZURE_FOUNDRY_BASE_URLzTuple[Any, ...]Ú_REGISTRY_ROWSc              #  óP   K  — | ]  }t        |t        «      r|nt        |Ž –— Œ  y ­w©N)Ú
isinstancerß   rö   )Ú.0Úrs     rÔ   ú	<genexpr>rp  ù   s&   è ø€ ÒlÐXYœ: a¬Ô8‘aÔ>OÐQRÐ>SÓSÑlùs   ‚$&zDict[str, ProviderConfig]ÚPROVIDER_REGISTRY)Úatomic_config_writeÚget_hermes_homeÚget_config_pathÚread_raw_configÚ$require_readable_config_before_write)Úget_plugin_oauth_auth_statusÚregistry_lookupÚsync_plugin_provider_registryc                 ón   ‡— ddl mŠ t        d   j                  } t	        d„ ˆfd„| D «       D «       d«      S )u…  First usable Anthropic credential (``.env`` preferred over a stale shell export), or ``""``.

    Order mirrors ``PROVIDER_REGISTRY["anthropic"].api_key_env_vars``.

    Checks both the ``.env`` file and the process environment, preferring ``~/.hermes/.env`` so a deliberate
    key rotation isn't shadowed by a stale shell export (matches the api-key resolution path â€” see #20591).
    r   ©Úget_env_value_prefer_dotenvr/  c              3  ó&   K  — | ]	  }|sŒ|–— Œ y ­wrl  rê   ©rn  Úvs     rÔ   rp  z$get_anthropic_key.<locals>.<genexpr>  s   è ø€ Ò^�qÒ\]”Ñ^ùó   ‚Šc              3  ó6   •K  — | ]  } ‰|«      xs d –— Œ y­w©rÈ   Nrê   )rn  Úvarr|  s     €rÔ   rp  z$get_anthropic_key.<locals>.<genexpr>  s   øè ø€ ÒXÈÑ8¸Ó=ÒCÀÓCÑXùó   ƒrÈ   )Úhermes_cli.configr|  rq  rì   Únext)Úenv_varsr|  s    @rÔ   Úget_anthropic_keyrˆ    s2   ø€ õ >Ü  Ñ-×>Ñ>€HÜÑ^ÓXÈxÔXÔ^Ð`bÓcÐcrô   >   ú**ú***úyour-api-keyÚ*ÚnoneÚnullÚdummyÚexampleÚchangemeÚplaceholderÚyour_api_keyÚyour_api_key_here)zsk-Úghp_Úhf_c                óŽ  — | j                  «       }|j                  d«      r|j                  d«      ryt        D ]9  }|j                  |«      sŒ|t	        |«      d }|sŒ&t        d„ |D «       «      sŒ9 y |j                  dd«      j                  dd«      j                  d	d«      }t        |«      xr t        d
„ |D «       «      S )zETrue for the placeholder shapes shipped in .env.example and the docs.Úyour_Ú_hereTNc              3  ó&   K  — | ]	  }|d k(  –— Œ y­w©ÚxNrê   ©rn  Úcs     rÔ   rp  z(_is_placeholder_shape.<locals>.<genexpr>/  s   è ø€ Ò3¨˜A �HÑ3ùó   ‚ú rÈ   ú-Ú_c              3  ó&   K  — | ]	  }|d k(  –— Œ y­wr›  rê   r�  s     rÔ   rp  z(_is_placeholder_shape.<locals>.<genexpr>2  s   è ø€ Ò!=¨q ! s¥(Ñ!=ùrŸ  )rÏ   Ú
startswithÚendswithÚ_PLACEHOLDER_KEY_PREFIXESÚlenÚallÚreplaceÚbool)ÚvalueÚloweredÚprefixÚtailÚstrippeds        rÔ   Ú_is_placeholder_shaper°  '  s±   € à�k‰k‹m€GØ×Ñ˜'Ô" w×'7Ñ'7¸Ô'@ØÜ+ò ˆØ×Ñ˜fÕ%Øœ3˜v›;˜<Ð(ˆDÚœÑ3¨dÔ3Õ3Ùð	ð
 �‰˜s BÓ'×/Ñ/°°RÓ8×@Ñ@ÀÀbÓI€HÜ�‹>Ò=œcÑ!=°HÔ!=Ó=Ð=rô   é   )Ú
min_lengthc               ó¬   — t        | t        «      sy| j                  «       }t        |«      |k\  xr$ |j	                  «       t
        vxr t        |«       S )zIReturn True when a configured secret looks usable, not empty/placeholder.F)rm  rØ   rÙ   r§  rÏ   Ú_PLACEHOLDER_SECRET_VALUESr°  )r«  r²  Úcleaneds      rÔ   Úhas_usable_secretr¶  5  sO   € ä�eœSÔ!ØØ�k‰k‹m€GÜ�‹L˜JÑ&ò 3Ø—‘“Ô'AÐAò3ä)¨'Ó2Ð2ð4rô   Ú
openrouter)zsk-or-zDict[str, tuple]ÚKNOWN_PROVIDER_KEY_PREFIXESc                ó   ‡— t        |xs d«      j                  «       Št        ‰«      syt        j	                  | «      }|r<t        ˆfd„|D «       «      s(t        j                  d|| dj                  |«      «       y‰S )zâ*value* stripped when it is a usable, prefix-valid secret; None (after warning on a provable
    prefix mismatch, so it never shadows a later credential source) otherwise. Providers without a
    declared prefix are fail-open.rÈ   Nc              3  ó@   •K  — | ]  }‰j                  |«      –— Œ y ­wrl  )r¤  )rn  ÚpÚvals     €rÔ   rp  z*_usable_declared_secret.<locals>.<genexpr>P  s   øè ø€ Ò@°!˜CŸN™N¨1×-Ñ@ùó   ƒz´Ignoring %s for provider %r: value does not match the expected key prefix (%s). Falling back to the next credential source. Fix or remove the malformed key to silence this warning.z or )	rØ   rÙ   r¶  r¸  ÚgetÚanyÚloggerÚwarningÚjoin)Úprovider_idr«  ÚsourceÚprefixesr¼  s       @rÔ   Ú_usable_declared_secretrÆ  H  su   ø€ ô ˆeŠk�rÓ
×
 Ñ
 Ó
"€CÜ˜SÔ!ØÜ*×.Ñ.¨{Ó;€HÙœÓ@°xÔ@Ô@Ü�‰ð@ð �K §¡¨XÓ!6ô		8ð
 Ø€Jrô   c                ó~  — 	 ddl m}  |«       xs i j                  d«      }t	        |t
        «      syt        |j                  d«      xs d«      j                  «       j                  «       | k7  ryt        |j                  d«      xs |j                  d«      xs d«      j                  «       S # t        $ r Y yw xY w)uA  ``model.key_env`` when config.yaml's main model targets *provider_id*, else ``""``.

    The Desktop settings UI saves registry-provider keys as a credential pointer
    (``model.key_env`` â†’ ``$HERMES_HOME/.env``) instead of the registry's canonical env var,
    so credential resolution must consult it (#106336).
    r   ©Úload_configÚmodelrÈ   ÚproviderÚkey_envÚapi_key_env)	r…  rÉ  r¾  rÑ   rm  ró   rØ   rÙ   rÏ   )rÃ  rÉ  Ú	model_cfgs      rÔ   Ú_model_level_key_envrÏ  Z  s¤   € ðÝ1Ù “]Ò( b×-Ñ-¨gÓ6ˆ	ô �i¤Ô&ØÜ
ˆ9�=‰=˜Ó$Ò*¨Ó+×1Ñ1Ó3×9Ñ9Ó;¸{ÒJØÜˆy�}‰}˜YÓ'ÒM¨9¯=©=¸Ó+GÒMÈ2ÓN×TÑTÓVÐVøô ò Ùðús   ‚ B0 Â0	B<Â;B<c                ó  ‡— | dk(  r&	 ddl m}m}  |«       \  }}|r ||«      \  }}||fS 	 yddlm}	 t        | «      }
|
rt        |  |	|
«      |
«      }|r||
fS |j                  D ]  }t        |  |	|«      |«      }|sŒ||fc S  d| › �}	 dd	lm}  || «      }|rŸ|j                  «       r�|j                  «       }|�|gng }	 |j!                  «       D ]+  Š‰€Œt#        ˆfd
„|D «       «      sŒ|j%                  ‰«       Œ- 	 |D ]3  }t'        |dd«      xs t'        |dd«      }t        | ||«      }|sŒ/||fc S  y# t        $ r }t        j                  d|«       Y d}~yd}~wt        $ r Y yw xY w# t        $ r Y Œzw xY w# t        $ r Y yw xY w)zDResolve an API-key provider's token and indicate where it came from.r  r   ©Úresolve_copilot_tokenÚget_copilot_api_tokenz#Copilot token validation failed: %sN)rÈ   rÈ   r{  zcredential_pool:©Ú	load_poolc              3  ó&   •K  — | ]  }‰|u–— Œ
 y ­wrl  rê   )rn  rž  ré   s     €rÔ   rp  z3_resolve_api_key_provider_secret.<locals>.<genexpr>�  s   øè ø€ Ò0TÀA°¸a´Ñ0Tùs   ƒÚaccess_tokenrÈ   Úruntime_api_key)Úhermes_cli.copilot_authrÒ  rÓ  Ú
ValueErrorrÀ  rÁ  rÑ   r…  r|  rÏ  rÆ  rì   Úagent.credential_poolrÕ  Úhas_credentialsÚpeekÚentriesr¨  ÚappendÚgetattr)rÃ  ÚpconfigrÒ  rÓ  ÚtokenrÄ  Ú	api_tokenÚ	_base_urlÚexcr|  rÌ  r¼  Úenv_varÚpool_sourcerÕ  ÚpoolÚentryÚ
candidatesÚkeyré   s                      @rÔ   Ú _resolve_api_key_provider_secretrì  m  sì  ø€ à�iÒð		ß\Ù1Ó3‰MˆE�6ÙÙ'<¸UÓ'CÑ$�	˜9Ø  &Ð(Ð(ð ð õ >ô # ;Ó/€GÙÜ% kÑ3NÈwÓ3WÐY`ÓaˆÙØ˜�<Ðà×+Ñ+ò  ˆÜ% kÑ3NÈwÓ3WÐY`ÓaˆÚð ˜�<Òð ð % [ MÐ2€KðÝ3Ù˜Ó%ˆÙ�D×(Ñ(Ô*Ø—I‘I“KˆEØ$)Ð$5˜%™¸2ˆJðØ!Ÿ\™\›^ò 1�EØÑ(¬SÓ0TÈÔ0TÕ-TØ"×)Ñ)¨%Õ0ñ1ð
 $ò ,�Ü˜e ^°RÓ8Òa¼GÀEÐK\Ð^`Ó<a�Ü-¨k¸3ÀÓL�ÚØ Ð+Ò+ð	,ð øôc ò 	GÜ�N‰NÐ@À#×FÐFð ûô ò 	ØØð	ûôL ò Ùðûô ò ØØðúsk   ˆ"D; Â7F  ÃE1 ÃE1 Ã.E1 Ä1F  Ä3F  Ä9F  Ä;	E.ÅEÅE.Å-E.Å1	E=Å:F  Å<E=Å=F  Æ 	FÆFc                ój   — t        | t        «      xr" | j                   xr | j                  t        k(  S )z°True when an :class:`AuthError` is upstream rate-limiting / quota: transient, and
    re-authenticating cannot fix it, so callers should say "retry later", not ``hermes auth``.)rm  rÄ   Úrelogin_requiredÚcoderÃ   ©Úerrors    rÔ   Úis_rate_limited_auth_errorrò  ­  s5   € ô �uœiÓ(ò 6°×1GÑ1GÐ-Gò 6Ø—
‘
Ô5Ñ5ð7rô   c                ó   — t        | «      ryy)a  ``(log_phrase, user_phrase)`` for a primary-provider failure that triggers the fallback
    chain. A 429/quota AuthError leaves the credentials valid; labelling it "auth failed" sends
    operators hunting for an expired token (#117482), so it reads as quota at every surface.)zrate-limited (429)z Primary provider quota exhausted)zauth failedzPrimary auth failed)rò  rð  s    rÔ   Úprimary_failure_wordingrô  ´  s   € ô " %Ô(ØGØ/rô   zWNo active paid subscription found. Please purchase/activate a subscription, then retry.zESubscription credits are exhausted. Top up/renew credits, then retry.)Úsubscription_requiredÚinsufficient_credits>   Úaccount_missingÚno_usable_creditsÚsubscription_expiredÚmember_spend_cap_exceededc                óh  — t        | t        «      rt        | «      rt        | «      S | j                  rddlm} | › d |«       › d�S | j                  t        v r=| j                  dk(  rt        | «      S t        j                  | j                  «      }|r|S | j                  dk(  r| › d�S t        | «      S )z2Map auth failures to concise user-facing guidance.r   )Úprofile_cli_selectorz Run `hermes zmodel` to re-authenticate.r÷   Útemporarily_unavailablez Please retry in a few seconds.)rm  rÄ   rò  rØ   rî  Úhermes_constantsrü  rï  Ú_ENTITLEMENT_ERROR_CODESrË  rA   Ú_GENERIC_ENTITLEMENT_MESSAGESr¾  )rñ  rü  Úgenerics      rÔ   Úformat_auth_errorr  Æ  s¨   € ä�eœYÔ'Ô+EÀeÔ+Lä�5‹zÐØ×Òå9à�˜Ñ&:Ó&<Ð%=Ð=WÐXÐXØ‡z�zÔ-Ñ-Ø�>‰>˜VÒ#Ü6°uÓ=Ð=Ü/×3Ñ3°E·J±JÓ?ˆÙØˆNØ‡z�zÐ.Ò.Ø�Ð7Ð8Ð8Üˆu‹:Ðrô   c                óX   — t        | t        «      xr t        | j                  «       «      S rl  )rm  rØ   rª  rÙ   )r«  s    rÔ   Ú_nonempty_strr  Û  s   € Ü�eœSÓ!Ò9¤d¨5¯;©;«=Ó&9Ð9rô   c                 óÄ   — t        «       dz  } t        j                  j                  d«      r3t	        | t        j                  «       dz  dz  «      rt        d| › d�«      ‚| S )Nú	auth.jsonÚPYTEST_CURRENT_TESTú.hermesz8Refusing to touch real user auth store during test run: zq. Set HERMES_HOME to a tmp_path in your test fixture, or run via scripts/run_tests.sh for hermetic CI-parity env.)rs  ÚosÚenvironr¾  Ú
_same_pathr   ÚhomeÚRuntimeError©rÚ   s    rÔ   Ú_auth_file_pathr  á  sf   € ÜÓ˜{Ñ*€Dô 	�
‰
�‰Ð,Ô-Ü˜4¤§¡£¨yÑ!8¸;Ñ!FÔGÜØFÀtÀfð MCð CóDð 	Dð €Krô   c                 ór   — 	 ddl m}   | «       }t        t	        «       |«      rdS |dz  S # t        $ r Y yw xY w)z¹Global-root auth.json in profile mode; None when profile and global root are the same dir.

    Read-only fallback path, so no pytest seat belt here (it lives on ``_auth_file_path()``).r   )Úget_default_hermes_rootNr  )rþ  r  rÑ   r  rs  )r  Úglobal_roots     rÔ   Ú_global_auth_file_pathr  î  sE   € ðÝ<Ù-Ó/ˆô œoÓ/°Ô=ˆ4Ð\À;ÐQ\ÑC\Ð\øô ò Ùðús   ‚* ª	6µ6c                 ó„  — t        «       } | �| j                  «       sdai S 	 t        | j	                  d¬«      «      t        | j                  «       «      f}t        }|�|�|dd |k(  r|d   S t        j                  j                  d«      rlt        j                  j                  d«      rMt        t        j                  d   «      dz  dz  }	 | j	                  d¬«      |j	                  d¬«      k(  rdai S 	 	 t        | «      }|�g |¢|‘­a|S # t        $ r d}Y ŒÆw xY w# t        $ r Y Œ3w xY w# t        $ r dai cY S w xY w)	u§   Load the global-root auth store (read-only fallback, mtime-memoised); ``{}`` when absent or
    unreadable â€” a malformed global store must never break profile reads.NF©Ústricté   r  ÚHOMEr  r  )r  ÚexistsÚ_global_auth_store_cacherØ   Úresolver   ÚstatrÑ   r	  r
  r¾  r   Ú_load_auth_store)Úglobal_pathÚ	cache_keyÚcachedÚ	real_rootÚstores        rÔ   Ú_load_global_auth_storer#  ú  sl  € ô )Ó*€KØÐ +×"4Ñ"4Ô"6Ø#'Ð Øˆ	ðä�×#Ñ#¨5Ð#Ó1Ó2´NÀ;×CSÑCSÓCUÓ4VðFXˆ	ô &€FØÐ Ð!3¸¸rÀ¸
ÀiÒ8OØ�a‰yÐÜ	‡z�z‡~�~Ð+Ô,´·±·±ÀÔ1GÜœŸ™ FÑ+Ó,¨yÑ8¸;ÑFˆ	ð	Ø×"Ñ"¨%Ð"Ó0°I×4EÑ4EÈUÐ4EÓ4SÒSØ+/Ð(Ø�	ð Tð
Ü  Ó-ˆð ÐØ#6 YÐ#6°Ñ#6Ð Ø€Løô) ò ØŠ	ðûô ò 	Ùð	ûô ò Ø#'Ð ØŠ	ðús5   ¢4D Ã(D  Ã9D/ ÄDÄDÄ 	D,Ä+D,Ä/D?Ä>D?zDict[str, threading.local]Ú_auth_target_lock_holdersc                óv   — 	 | j                  d¬«      |j                  d¬«      k(  S # t        $ r | |k(  cY S w xY w)NFr  )r  rÑ   ©ÚleftÚrights     rÔ   r  r     sA   € ðØ�|‰| 5ˆ|Ó)¨U¯]©]À%¨]Ó-HÑHÐHøÜò Ø�u‰}Òðús   ‚$' §8·8c                ó^   — t        | |«      ry	 | j                  |«      S # t        $ r Y yw xY w)a4  True when two auth paths name ONE store rather than two copies.
    ``_same_path`` resolves symlinks and ``..``; ``samefile`` adds hardlinks and bind-mounts
    (same inode under two resolved names). Used by the forked-grant heal: a shared store has
    no "other side" to consolidate.

    See #101356.
    TF)r  ÚsamefileÚOSErrorr&  s     rÔ   Ú_is_same_auth_storer,  '  s7   € ô �$˜ÔØðØ�}‰}˜UÓ#Ð#øÜò Ùðús   �   	,«,c                ón   — 	 t        | j                  d¬«      «      S # t        $ r t        | «      cY S w xY w)zWCanonical string for *path* (resolved when possible) used as a cache / lock-holder key.Fr  )rØ   r  rÑ   r  s    rÔ   Ú_resolved_keyr.  7  s6   € ðÜ�4—<‘< u�<Ó-Ó.Ð.øÜò Ü�4‹yÒðús   ‚ �4³4c                óœ   — t         5  t        j                  t        | «      t	        j
                  «       «      cddd«       S # 1 sw Y   yxY w)zCReturn a reentrancy tracker keyed to one canonical auth-store path.N)Ú_auth_target_lock_holders_guardr$  Ú
setdefaultr.  Ú	threadingÚlocal©Útarget_paths    rÔ   Ú_auth_lock_holder_forr6  ?  s=   € ä	(ñ cÜ(×3Ñ3´MÀ+Ó4NÔPY×P_ÑP_ÓPaÓb÷c÷ cò cús   ‡1AÁAc                ór  — t         r[t        j                  | j                  «       |r&t         j                  t         j                  z  «       yt         j
                  «       y| j                  d«       t        j                  | j                  «       |rt        j                  nt        j                  d«       y)zcNon-blocking exclusive flock (fcntl) or 1-byte msvcrt lock at offset 0; ``acquire=False`` releases.r   é   N)ÚfcntlÚflockÚfilenoÚLOCK_EXÚLOCK_NBÚLOCK_UNÚseekÚmsvcrtÚlockingÚLK_NBLCKÚLK_UNLCK)Ú	lock_fileÚacquires     rÔ   Ú_kernel_lockrF  E  si   € åÜ�‰�I×$Ñ$Ó&É7¬¯©¼¿¹Ñ)FÕfÔX]×XeÑXeÕfà�‰�qÔÜ�‰�y×'Ñ'Ó)¹g¬6¯?ª?Ì6Ï?É?Ð\]Õ^rô   c              #  ó4  K  — t        |dd«      dkD  r0|xj                  dz  c_        	 d–— |xj                  dz  c_        y| j                  j                  dd¬«       t	        «       5 }d}t
        €t        �¡t        rA| j                  «       r| j                  «       j                  dk(  r	 | j                  dd¬	«       |j                  | j                  t        rd
ndd¬	«      «      }t        j                   «       t#        d|«      z   }	 	 t%        |d«       	 d|_        	 d–— d|_        |�	 t%        |d«       ddd«       y# |xj                  dz  c_        w xY w# t        t        f$ r Y Œ°w xY w# t&        t        t        f$ r: t        j                   «       |k\  rt)        |«      ‚t        j*                  d«       Y nw xY wŒº# t        t,        f$ r Y Œ›w xY w# d|_        |�#	 t%        |d«       w # t        t,        f$ r Y w w xY ww xY w# 1 sw Y   yxY w­w)aH  Cross-process advisory flock helper, reentrant per-thread via ``holder.depth``.

    Falls back to a depth-only guard when neither ``fcntl`` nor ``msvcrt`` is available. Callers
    supply their own ``threading.local`` so independent locks (profile store vs global root vs the
    shared Nous store) track reentrancy separately.Údepthr   r8  NT©ÚparentsÚexist_okr   úutf-8©Úencodingzr+za+g      ð?gš™™™™™©?F)rà  rH  ÚparentÚmkdirr   r9  r@  r  r  Úst_sizeÚ
write_textr+  ÚPermissionErrorÚenter_contextÚopenÚtimeÚ	monotonicÚmaxrF  ÚBlockingIOErrorÚTimeoutErrorÚsleepÚIOError)Ú	lock_pathÚholderÚtimeout_secondsÚtimeout_messageÚstackrD  Údeadlines          rÔ   Ú
_file_lockrc  N  s  è ø€ ô ˆv�w Ó" QÒ&Ø�Š˜Ñ�ð	Ûà�LŠL˜AÑ�LØà×Ñ×Ñ 4°$ÐÔ7Ü	‹ð  ˜Øˆ	ÜÐ¤Ð 2õ
 ˜y×/Ñ/Ô1°Y·^±^Ó5E×5MÑ5MÐQRÒ5RðØ×(Ñ(¨°wÐ(Ô?ð ×+Ñ+¨I¯N©NÅ6¹4ÈtÐ^e¨NÓ,fÓgˆIÜ—~‘~Ó'¬#¨c°?Ó*CÑCˆHØð%Ü  ¨DÔ1Øð ˆŒð	ÛàˆFŒLØÐ$ðÜ  ¨EÔ2÷= ð  øð	 �LŠL˜AÑŽLûô  ¤Ð1ò Ùðûô (¬´/ÐBò %Ü—~‘~Ó'¨8Ò3Ü*¨?Ó;Ð;Ü—J‘J˜tÖ$ð%úð	 øô"  ¤Ð)ò Ùðûð	 ˆFŒLØÐ$ðÜ  ¨EÕ2øÜ¤Ð)ò Ùðúð %ú÷9 ð  üsØ   ‚&H©E ­=HÁ*AHÂ-EÃ AHÄE4ÄHÄ"GÄ&	HÄ0GÄ<	HÅEÅHÅE1Å.HÅ0E1Å1HÅ4AGÆ?HÇGÇHÇGÇHÇGÇHÇ
H	Ç&G3Ç2H	Ç3H	ÈH	ÈH	ÈH	È	HÈHÈHr4  c             #  ó¦   K  — |�|n	t        «       }t        |j                  d«      t        |«      | d«      5  d–— ddd«       y# 1 sw Y   yxY w­w)ai  Cross-process advisory lock for one auth.json read/write transaction.

    ``target_path`` is required for profile-to-global write-throughs: each path has its own
    reentrancy tracker and kernel lock. Lock ordering invariant: ``_auth_store_lock`` FIRST (outer),
    ``_nous_shared_store_lock`` SECOND (inner), else deadlock against a concurrent shared import.Nz.lockz%Timed out waiting for auth store lock)r  rc  Úwith_suffixr6  )r_  r5  Ú	auth_paths      rÔ   Ú_auth_store_lockrg  ‚  sS   è ø€ ð  +Ð6‘¼OÓ<M€IÜ	Ø×Ñ˜gÓ&Ô(=¸iÓ(HÈ/Ø/ó
1ñ ó 	÷÷ ñ üs   ‚5A·A¼	AÁAÁ
Ac                 ó   — t         i dœS )N)ÚversionÚ	providers)r™   rê   rô   rÔ   Ú_empty_auth_storerk  ‘  s   € Ü)¸Ñ;Ð;rô   c                óæ  — | xs
 t        «       } | j                  «       s
t        «       S 	 t        j                  | j                  d¬«      «      }t        |t        «      rt        |j!                  d«      t        «      st        |j!                  d«      t        «      rA|j#                  di «       t        |j!                  d«      t        «      rt%        |d   «       |S t        |t        «      rIt        |j!                  d«      t        «      r*|d   }d|v rd|d   ini }i t        «       ¥||rddœ¥S d dœ¥S t        «       S # t        $ r t        j                  d| d¬«       ‚ t        $ r…}| j                  d«      }	 t        j                  | |«       d}n)# t        $ r d}t        j                  d|d¬«       Y nw xY wt        j                  d	| ||rd
nd|«       t        «       cY d }~S d }~ww xY w)Nz	utf-8-sigrM  zbauth: could not read %s, leaving the store on disk untouched rather than degrading to an empty oneT)Úexc_infoz.json.corruptFz:auth: could not preserve a copy of the corrupt store at %sz?auth: failed to parse %s (%s), starting with empty store. %s %szCorrupt file preserved atz A copy could NOT be preserved atrj  Úcredential_poolÚsystemsÚnous_portalr÷   )rj  Úactive_provider)r  r  rk  ÚjsonÚloadsÚ	read_textr+  rÀ  rÁ  rÑ   re  ÚshutilÚcopy2Údebugrm  ró   r¾  r1  rE   )Ú	auth_fileÚrawrå  Úcorrupt_pathÚ	preservedro  rj  s          rÔ   r  r  •  sè  € ØÒ.œ_Ó.€IØ×ÑÔÜ Ó"Ð"ð#Ü�j‰j˜×,Ñ,°kÐ,ÓBÓCˆô8 �#”tÔÜ�3—7‘7˜;Ó'¬Ô.´*¸S¿W¹WÐEVÓ=WÔY]Ô2^Ø�‰�{ BÔ'Ü�c—g‘g˜kÓ*¬DÔ1Ü*¨3¨{Ñ+;Ô<Øˆ
ä�#”tÔ¤¨C¯G©G°IÓ,>ÄÔ!EØ�i‘.ˆØ8EÈÑ8P�V˜W ]Ñ3Ñ4ÐVXˆ	ðBÔ#Ó%ð B°IÙ-6 6òBð 	BØ<@òBð 	BäÓÐøôO ò ô 	�‰ð4à ð 	ô 	&ð 	Üò #ð !×,Ñ,¨_Ó=ˆð	(Ü�L‰L˜ LÔ1Ø‰IøÜò 	(ØˆIÜ�L‰LÐUÐWcØ"&ð ö (ð	(úô 	�‰ØMØ�sÙ+4Ñ'Ð:\Øô		ô
 !Ó"Õ"ûð!#úsA   ª%E Å*G0Å+G+Å=FÆG+Æ#F<Æ9G+Æ;F<Æ<)G+Ç%G0Ç+G0F©Ú	fsync_dirc               ój   — ddl m}  || j                  «       t        | «       t	        | |fd|dœ|¤Ž y)zÀ0600 credential JSON under a 0700 parent (``secure_parent_dir`` refuses ``/``, top-level dirs
    and the install tree). ``atomic_json_write`` creates the temp file 0600 before any byte lands.r   )Úmkdir_under_hermes_homei€  )Úmoder}  N)rþ  r  rO  r   r   )ÚtargetÚdatar}  Údump_kwargsr  s        rÔ   Ú_save_private_jsonr„  Å  s1   € õ 9Ù˜FŸM™MÔ*Ü�fÔÜ�f˜dÐS¨¸)ÑSÀ{ÓSrô   c                óÀ   — |�|n	t        «       }t        | d<   t        j                  t        j
                  «      j                  «       | d<   t        || d¬«       |�da|S )z¿Atomically persist *auth_store* (0o600, parent tightened to 0o700) to the active store, or to
    an explicit *target_path* (e.g. the global-root write-through for rotating xAI OAuth grants).Nri  Ú
updated_atTr|  )	r  r™   r	   Únowr
   ÚutcÚ	isoformatr„  r  )Ú
auth_storer5  rx  s      rÔ   Ú_save_auth_storer‹  Î  s]   € ð  +Ð6‘¼OÓ<M€IÜ.€JˆyÑÜ'Ÿ|™|¬H¯L©LÓ9×CÑCÓE€Jˆ|ÑÜ�y *¸Õ=ØÐð $(Ð ØÐrô   c                óV   — | j                  |«      }t        |t        «      si x}| |<   |S )zRReturn ``auth_store[key]`` as a dict, replacing a missing/non-dict value in place.©r¾  rm  ró   )rŠ  rë  Úsections      rÔ   Ú_store_sectionr�  Ý  s-   € à�n‰n˜SÓ!€GÜ�gœtÔ$Ø$&Ð&ˆ�*˜S‘/Ø€Nrô   c                ó¬   — | r| j                  d«      nd}t        |t        «      r|j                  |«      nd}t        |t        «      rt        |«      S dS )zQShallow copy of ``store["providers"][provider_id]`` when it is a dict, else None.rj  Nr�  )r"  rÃ  rj  Ústates       rÔ   Ú_provider_state_inr’  å  sE   € á*/�—	‘	˜+Ô&°T€IÜ*4°YÄÔ*EˆI�M‰M˜+Ô&È4€EÜ$ U¬DÔ1Œ4�‹;Ð;°tÐ;rô   c                ó~   — t        | |«      }|�|t        «       fS t        t        «       |«      }|�|t        «       fS dS )zÜProvider state plus the auth.json path it came from (profile first, then the global root).

    Refresh paths that rotate single-use OAuth refresh tokens must write the updated chain back to
    the same store they read.©NN)r’  r  r#  r  )rŠ  rÃ  r‘  Úglobal_states       rÔ   Ú _load_provider_state_with_sourcer–  ì  sN   € ô ˜z¨;Ó7€EØÐØ”oÓ'Ð'Ð'Ü%Ô&=Ó&?ÀÓM€LØ7CÐ7OˆLÔ0Ó2Ð3ÐaÐUaÐarô   c                ó    — t        | |«      d   S )z¼Provider state; in profile mode falls back to the global-root ``auth.json`` per provider (same
    shadowing as ``read_credential_pool``), so profile workers see globally-authed providers.r   )r–  )rŠ  rÃ  s     rÔ   Ú_load_provider_stater˜  ú  s   € ô ,¨J¸ÓDÀQÑGÐGrô   c              #  óD  K  — t        |«      5  t        «       }t        || «      \  }}|�t        |t	        «       «      r|||f–— 	 ddd«       yt        ||¬«      5  |t        t        |«      | «      |f–— ddd«       ddd«       y# 1 sw Y   ŒxY w# 1 sw Y   yxY w­w)ao  Lock the active auth store and any global fallback source, in that order.

    Re-reading the source after its lock is acquired prevents stale refreshes and whole-file lost
    updates without inverting the documented auth -> shared lock order. ``timeout_seconds`` applies
    to BOTH locks: a transaction that spans a network call must let waiters outlive that call.Nr4  )rg  r  r–  r  r  r’  )rÃ  r_  rŠ  r‘  Úsource_paths        rÔ   Ú_provider_state_transactionr›     s·   è ø€ ô 
˜/Ó	*ñ jÜ%Ó'ˆ
Ü=¸jÈ+ÓVÑˆˆ{ØÐ¤*¨[¼/Ó:KÔ"LØ˜e [Ð0Ò0Ø÷jð jô ˜o¸;ÔGñ 	jØÔ0Ô1AÀ+Ó1NÐP[Ó\Ð^iÐiÒi÷	j÷jð j÷	jð 	jú÷jð jüs@   ‚B Ž8BÁ	B ÁBÁBÁ7BÁ?	B ÂB	ÂBÂBÂB T©Ú
set_activec               ó2   — |t        | d«      |<   |r|| d<   y y )Nrj  rq  )r�  )rŠ  rÃ  r‘  r�  s       rÔ   Ú_store_provider_staterŸ    s)   € ð <A„N�:˜{Ó+¨KÑ8ÙØ(3ˆ
Ð$Ò%ð rô   c                ó"   — t        | ||d¬«       y)zMWrite *state* under ``providers`` and make *provider_id* the active provider.Trœ  N)rŸ  )rŠ  rÃ  r‘  s      rÔ   Ú_save_provider_stater¡    s   € ä˜* k°5ÀTÖJrô   c                ó†   — t        «       5  t        «       }t        || |«       t        |«      cddd«       S # 1 sw Y   yxY w)zTLock, load, write *state* as the active provider, save. Returns the auth store path.N)rg  r  r¡  r‹  )rÃ  r‘  rŠ  s      rÔ   Ú_save_active_provider_stater£    s9   € ä	Ó	ñ ,Ü%Ó'ˆ
Ü˜Z¨°eÔ<Ü 
Ó+÷,÷ ,ò ,ús	   ‹"7·A c               ó¦   — t        |¬«      5  t        |«      }t        || t        |«      |¬«       t	        ||¬«      cddd«       S # 1 sw Y   yxY w)zFMerge one provider into a specific auth store under that store's lock.r4  rœ  N)rg  r  rŸ  ró   r‹  )rÃ  r‘  r5  r�  rŠ  s        rÔ   Ú _persist_provider_state_to_storer¥  '  sK   € ô 
 kÔ	2ñ EÜ% kÓ2ˆ
Ü˜j¨+´t¸E³{ÈzÕZÜ 
¸ÔD÷E÷ Eò Eús   �0AÁAc                ó„   — |�t        |t        «       «      rt        | ||d¬«       t        | «       yt	        |||d¬«       y)a@  Persist provider state back to the auth store it was read from.

    A token refresh rewrites credentials, not the user's choice of provider: ``active_provider`` is
    left as it is (a Nous free-tier identity refreshed for a connector call must not become the
    inference provider of an install that has its own key).NFrœ  )r  r  rŸ  r‹  r¥  )rŠ  rÃ  r‘  rš  s       rÔ   Ú_save_provider_state_to_sourcer§  1  s;   € ð Ðœj¨´oÓ6GÔHÜ˜j¨+°uÈÕOÜ˜Õ$ä(¨°e¸[ÐUZÖ[rô   c                ó¼   — t        «       5  t        «       }|j                  d«      xs dj                  «       s| |d<   t	        |«       ddd«       y# 1 sw Y   yxY w)zèSet ``active_provider`` only when none is set yet: the first ``hermes auth add`` credential must
    make its provider active (else setup reports "No inference provider configured"); later adds
    leave the user's choice untouched.rq  rÈ   N)rg  r  r¾  rÙ   r‹  )rÃ  rŠ  s     rÔ   Úmark_provider_active_if_unsetr©  @  sU   € ô 
Ó	ñ )Ü%Ó'ˆ
Ø—‘Ð0Ó1Ò7°R×>Ñ>Ô@Ø,7ˆJÐ(Ñ)Ü˜ZÔ(÷	)÷ )ñ )ús   ‹>AÁAc                ót   — | xs dj                  «       j                  «       }t        |«      d uxs |t        v S ©NrÈ   )rÙ   rÏ   Ú_registry_lookuprÀ   ©rÃ  Ú
normalizeds     rÔ   Úis_known_auth_providerr¯  K  s9   € ØÒ# ×*Ñ*Ó,×2Ñ2Ó4€JÜ˜JÓ'¨tÐ3Ò[°zÔE[Ð7[Ð[rô   c                ó¨   — | xs dj                  «       j                  «       }|t        v rt        |   j                  S t	        j
                  || «      S r«  )rÙ   rÏ   rq  rá   rÀ   r¾  r­  s     rÔ   Úget_auth_provider_display_namer±  P  sK   € ØÒ# ×*Ñ*Ó,×2Ñ2Ó4€JØÔ&Ñ&Ü  Ñ,×1Ñ1Ð1Ü!×%Ñ% j°+Ó>Ð>rô   c                ó°   — | xs dj                  «       j                  «       }|sy|dv s|j                  d«      ry	 t        |«       y# t        $ r Y yw xY w)zÈWhether runtime resolution recognizes a provider identity (a capability check, not a credential
    check): ``resolve_provider`` normalization plus the special runtime identities outside the registry.rÈ   F>   ÚmoaÚautoÚcustomr·  úcustom:T)rÙ   rÏ   r¤  Úresolve_providerrÄ   r­  s     rÔ   Úis_runtime_provider_routabler¸  W  sf   € ð Ò# ×*Ñ*Ó,×2Ñ2Ó4€JÙØØÐ<Ñ<À
×@UÑ@UÐV_Ô@`ØðÜ˜Ô$ð øô ò Ùðús   ½A	 Á		AÁAc                óF  — t        «       j                  d«      }t        |t        «      r|ni }t	        «       j                  d«      }t        |t        «      r|ni }| €jt        |«      }|j                  «       D ]J  \  }}|j                  |«      }t        |t        «      r|sŒ*t        |t        «      r|rŒ=t        |«      ||<   ŒL |S |j                  | «      }t        |t        «      r|rt        |«      S |j                  | «      }t        |t        «      rt        |«      S g S )a  Return the persisted credential pool, or one provider slice.

    In profile mode the global-root ``auth.json`` is a read-only fallback applied per provider ONLY
    when the profile has zero entries for it (``hermes auth add`` in the profile shadows global).rn  )r  r¾  rm  ró   r#  ÚitemsÚlist)	rÃ  rè  Úglobal_poolÚmergedÚgp_keyÚ
gp_entriesÚexistingÚprovider_entriesÚglobal_entriess	            rÔ   Úread_credential_poolrÃ  f  s  € ô
 Ó×!Ñ!Ð"3Ó4€DÜ˜d¤DÔ)‰4¨r€DÜ)Ó+×/Ñ/Ð0AÓB€KÜ!+¨K¼Ô!>‘+ÀB€KàÐÜ�d“ˆØ"-×"3Ñ"3Ó"5ò 	2ÑˆF�JØ—z‘z &Ó)ˆHÜ˜z¬4Ô0±ZØÜ˜x¬Ô.²8Ü!% jÓ!1��v’ð	2ð ˆà—x‘x Ó,ÐÜÐ"¤DÔ)Ñ.>ÜÐ$Ó%Ð%Ø —_‘_ [Ó1€NÜ#-¨n¼dÔ#CŒ4�ÓÐKÈÐKrô   )Úlast_statusÚlast_status_atÚlast_error_codeÚlast_error_reasonÚlast_error_messageÚlast_error_reset_atÚstatus_cleared_atc                ó0  — t        |t        «      s| S 	 ddlm}m}m}m}m} ddlm	}  ||j                  d«      | j                  d«      «      }	|	ri | ¥d|	i¥n| }
t        D �ci c]  }||j                  |«      “Œ }} || j                  d«      «      xs d} ||j                  d«      «      xs d}| j                  d«      ||fv r||kD  ri |
¥|¥S |j                  d«      }|||fvr|
S | j                  d	«      xs d
}|j                  d	«      xs d
}|r	|r||k7  r| S  ||j                  d«      «      xs d}||k  r|
S ||k(  r3 ||j                  ||«      «      }|�|t        j                  «       k  r|
S i |
¥|¥S c c}w # t        $ r | cY S w xY w)ac  Keep a newer on-disk cooldown/quarantine over a stale in-memory one.

    ``write_credential_pool`` persists an in-memory snapshot that may predate another process
    marking the same credential exhausted/dead; without this merge the later rewrite resurrects a
    rate-limited key as healthy and both processes resume hammering it. The mirror image is a
    ``hermes auth reset`` that postdates the snapshot's cooldown (``status_cleared_at`` newer than
    its ``last_status_at``): the disk row wins there too, or a live session's next ordinary flush
    would write the reset cooldown straight back (#89415).r   )ÚPooledCredentialÚSTATUS_DEADÚSTATUS_EXHAUSTEDÚ_exhausted_untilÚ_parse_absolute_timestamp)Úmerge_model_cooldownsÚmodel_cooldownsrÅ  g        rÊ  rÄ  r×  rÈ   )rm  ró   rÛ  rÌ  rÍ  rÎ  rÏ  rÐ  Ú%agent.credential_pool_model_cooldownsrÑ  r¾  Ú_POOL_STATUS_FIELDSÚ	from_dictrV  rÑ   )ré  Ú
disk_entryrÃ  rÌ  rÍ  rÎ  rÏ  rÐ  rÑ  Úmerged_cooldownsr½  ÚfÚdisk_status_fieldsÚmem_tsÚ
cleared_tsÚdisk_statusÚ
mem_accessÚdisk_accessÚdisk_tsÚuntils                       rÔ   Ú_merge_disk_cooldown_staterá  †  sÐ  € ô �j¤$Ô'Øˆð"÷	
õ 	
õ 	PÙ0°·±Ð@QÓ1RÐTY×T]ÑT]Ð^oÓTpÓqÐÙCSÐ?�EÐ?Ð,Ð.>Ò?ÐY^ˆÜ<OÖP°q˜a §¡°Ó!2Ñ2ÐPÐÐPá*¨5¯9©9Ð5EÓ+FÓGÒNÈ3ˆÙ.¨z¯~©~Ð>QÓ/RÓSÒZÐWZˆ
Ø�9‰9�]Ó#¨Ð5EÐ'FÑFÈ:ÐX^ÒK^Ø3�fÐ3Ð 2Ð3Ð3Ø —n‘n ]Ó3ˆØ˜{Ð,<Ð=Ñ=ØˆMð —Y‘Y˜~Ó.Ò4°"ˆ
Ø —n‘n ^Ó4Ò:¸ˆÙ™+¨*¸Ò*CØˆLÙ+¨J¯N©NÐ;KÓ,LÓMÒTÐQTˆØ�fÒØˆMØÐ*Ò*Ù$Ð%5×%?Ñ%?ÀÈZÓ%XÓYˆEØˆ} ¬¯©«Ò 4Ø�Ø/�&Ð/Ð.Ð/Ð/ùò- Qøô. ò ØŠðúsC   ”AF Á#FÁ<AF ÃF Ã-4F Ä"!F Å7F Å<F ÆF ÆFÆFc                ó’   — | D �ci c]7  }t        |t        «      sŒ|j                  d«      sŒ&|j                  d«      |“Œ9 c}S c c}w )Nrà   )rm  ró   r¾  )rÞ  Úes     rÔ   Ú
_entry_idsrä  ¸  s5   € Ø$+ÖS˜q¬z¸!¼TÕ/BÀqÇuÁuÈTÅ{ˆA�E‰E�$‹K˜‰NÒSÐSùÒSs   …A›A­A)Úremoved_idsÚstatus_cleared_idsc               óN  — |xs dD �ch c]  }|sŒ|’Œ	 }}t        «       5  t        «       }t        |d«      }|D �cg c]   }t        |t        «      rt        || «      n|‘Œ" }	}|j                  | «      }
t        |
t        «      r|
ng }
t        |
«      }t        t        |	«      «      }|xs dD �ch c]  }|sŒ|’Œ	 }}|	D �cg c]T  }t        |t        «      r@t        ||j                  d«      |v rdn|j                  |j                  d«      «      | «      n|‘ŒV }}|
D ]M  }t        |t        «      r|j                  d«      nd}|sŒ)||vsŒ.||vsŒ3|j                  t        || «      «       ŒO ||| <   t        |«      cddd«       S c c}w c c}w c c}w c c}w # 1 sw Y   yxY w)aL  Persist one provider's credential pool under auth.json.

    Final disk-boundary sanitizer for borrowed credentials (callers may pass raw dicts). Entries on
    disk but missing from *entries* (added concurrently) are merged back unless in *removed_ids*,
    so a rotation/exhaustion rewrite never drops a concurrent credential. Entries in
    *status_cleared_ids* were cleared deliberately (``hermes auth reset``) and skip the
    recency merge, which would otherwise read their cleared ``last_status_at`` (None ->
    epoch 0) as a stale snapshot and copy a still-binding cooldown back.rê   rn  rà   N)rg  r  r�  rm  ró   r   r¾  r»  rä  Úsetrá  rß  r‹  )rÃ  rÞ  rå  ræ  ÚridÚremovedrŠ  rè  rã  Ú	sanitizedÚexisting_listÚexisting_by_idÚnew_idsÚcidÚstatus_clearedr½  rÖ  Údisk_ids                     rÔ   Úwrite_credential_poolrò  ¼  sÇ  € ð  +Ò0¨bÖ9�s²SŠsÐ9€GÐ9Ü	Ó	ñ ,Ü%Ó'ˆ
Ü˜jÐ*;Ó<ˆð öàô EOÈqÔRVÔDWÔ0°°KÔ@Ð]^Ñ^ðˆ	ð ð Ÿ™ Ó-ˆÜ)3°MÄ4Ô)H™ÈbˆÜ# MÓ2ˆÜ”j Ó+Ó,ˆØ*<Ò*BÀÖK #Âsš#ÐKˆÐKð ö( ð
 ô ˜!œTÔ"ô 'Ø˜1Ÿ5™5 ›;¨.Ñ8‘4¸n×>PÑ>PÐQR×QVÑQVÐW[ÓQ\Ó>]Ð_jôð )*ñ*ð( ˆð ( ð (ò 	]ˆJÜ.8¸ÄTÔ.J�j—n‘n TÔ*ÐPTˆGÚ˜7¨'Ò1°gÀWÒ6LØ—‘ÔBÀ:È{Ó[Õ\ð	]ð #ˆˆ[ÑÜ 
Ó+÷-,ñ ,ùò :ùòùò Lùò( ÷,ð ,úsX   ‰F‘F¡F¼%FÁ!AFÂ/FÂ7FÂ;FÃAFÄ,FÅFÅFÅ,FÆFÆF$c                ó¶   — | j                  |«      }t        |t        «      r|S t        |t        «      r!|D �cg c]  }t	        |«      ‘Œ c}| |<   | |   S yc c}w )z�Canonical (list-form) suppressed sources for *provider_id*; a legacy mapping (keys = source
    names) is migrated to the list form in place.N)r¾  rm  r»  ró   rØ   )Ú
suppressedrÃ  Úraw_sourcesrá   s       rÔ   Ú_suppressed_source_liströ  ã  sY   € ð —.‘. Ó-€KÜ�+œtÔ$ØÐÜ�+œtÔ$Ø9DÖ"E°¤3 t¥9Ò"Eˆ
�;ÑØ˜+Ñ&Ð&Øùò #Fs   ¸Ac                óØ   — t        «       5  t        «       }t        |d«      }t        || «      }|€g x}|| <   ||vr|j	                  |«       t        |«       ddd«       y# 1 sw Y   yxY w)z@Mark a credential source as suppressed so it won't be re-seeded.Úsuppressed_sourcesN)rg  r  r�  rö  rß  r‹  ©rÃ  rÄ  rŠ  rô  Úprovider_lists        rÔ   Úsuppress_credential_sourcerû  ï  sq   € ä	Ó	ñ %Ü%Ó'ˆ
Ü# JÐ0DÓEˆ
Ü/°
¸KÓHˆØÐ Ø68Ð8ˆM˜J {Ñ3Ø˜Ñ&Ø× Ñ  Ô(Ü˜Ô$÷%÷ %ñ %ús   ‹AA Á A)c                óz   — 	 |t        «       j                  di «      j                  | g «      v S # t        $ r Y yw xY w)z=Check if a credential source has been suppressed by the user.rø  F)r  r¾  rÑ   )rÃ  rÄ  s     rÔ   Úis_source_suppressedrý  ü  sD   € ðØÔ)Ó+×/Ñ/Ð0DÀbÓI×MÑMÈkÐ[]Ó^Ð^Ð^øÜò Ùðús   ‚+. ®	:¹:c                ón  — t        «       5  t        «       }|j                  d«      }t        |t        «      s
	 ddd«       yt        || «      }|�||vr
	 ddd«       y|j                  |«       |s|j                  | d«       |s|j                  dd«       t        |«       	 ddd«       y# 1 sw Y   yxY w)zLClear a suppression marker so the source will be re-seeded on the next load.rø  NFT)	rg  r  r¾  rm  ró   rö  ÚremoveÚpopr‹  rù  s        rÔ   Úunsuppress_credential_sourcer    s±   € ä	Ó	ñ Ü%Ó'ˆ
Ø—^‘^Ð$8Ó9ˆ
Ü˜*¤dÔ+Ø÷	ð ô
 0°
¸KÓHˆØÐ  F°-Ñ$?Ø÷ð ð 	×Ñ˜VÔ$ÙØ�N‰N˜;¨Ô-ÙØ�N‰NÐ/°Ô6Ü˜Ô$Ø÷÷ ñ ús   ‹-B+ÁB+ÁAB+Â+B4c                ó*   — t        t        «       | «      S )zSPersisted auth state for a provider (profile first, global-root fallback), or None.)r˜  r  )rÃ  s    rÔ   Úget_provider_auth_stater    s   € äÔ 0Ó 2°KÓ@Ð@rô   c                 ó°   — 	 t        d«      xs i } | j                  d«      }t        |t        «      syt
        |j                  «       v S # t        $ r Y yw xY w)a•  Return True if the currently-held Nous token carries ``billing:manage``.

    Reads the persisted ``scope`` string saved at login (``_save_provider_state``
    stores ``token_data.get("scope") or scope``). A space-delimited match. Used by
    the lazy step-up: if False, the first billing call will 403 ``insufficient_scope``
    anyway, but checking up front lets a surface skip a doomed round-trip.
    r÷   Fræ   )r  rÑ   r¾  rm  rØ   rž   Úsplit)r‘  ræ   s     rÔ   Únous_token_has_billing_scoper    sX   € ðÜ'¨Ó/Ò5°2ˆð �I‰I�gÓ€EÜ�eœSÔ!ØÜ$¨¯©«Ð5Ð5øô ò Ùðús   ‚A	 Á		AÁAc                 ó4   — t        «       j                  d«      S )z8Return the currently active provider ID from auth store.rq  )r  r¾  rê   rô   rÔ   Úget_active_providerr  .  s   € äÓ×!Ñ!Ð"3Ó4Ð4rô   c                ó˜   — t        «       j                  d«      xs dj                  «       j                  «       }t	        |«      xr || k(  S )Nrq  rÈ   )r  r¾  rÙ   rÏ   rª  )r®  Úactives     rÔ   Ú_active_provider_isr  3  sA   € ÜÓ ×$Ñ$Ð%6Ó7Ò=¸2×DÑDÓF×LÑLÓN€FÜ�‹<Ò0˜F jÑ0Ð0rô   c                óŽ   — t        | t        «      xr4 | j                  d«      xs dj                  «       j	                  «       |k(  S )NrË  rÈ   )rm  ró   r¾  rÙ   rÏ   )Úslotr®  s     rÔ   Ú_slot_selectsr  8  s:   € Ü�dœDÓ!Ò` t§x¡x°
Ó';Ò'A¸r×&HÑ&HÓ&J×&PÑ&PÓ&RÐV`Ñ&`Ð`rô   c                óÒ  ‡ ‡— ddl m}  |«       }t        |j                  d«      ‰ «      ry|j                  d«      }t	        |t
        «      r#t        ˆ fd„|j                  «       D «       «      rydˆ fd„Š|j                  d«      }t	        |t
        «      sy	|j                  d
«      }t	        |t
        «      r|j                  «       nd} ‰|«      xs t        ˆfd„|D «       «      S )aÄ  config.yaml ``model.provider``, or a MoA advisor/aggregator slot naming the provider.

    MoA presets are explicit model selections too: ``provider: anthropic`` in a MoA slot opts into
    Anthropic credentials for that slot even when the main model is another provider; otherwise
    Claude Code OAuth entries get pruned by ``load_pool("anthropic")`` and MoA advisors fail with
    "no ANTHROPIC_API_KEY" while the picker says Anthropic is logged in.r   rÈ  rÊ  TÚ	auxiliaryc              3  ó6   •K  — | ]  }t        |‰«      –— Œ y ­wrl  ©r  ©rn  Úsr®  s     €rÔ   rp  z+_config_selects_provider.<locals>.<genexpr>J  s   øè ø€ Ò(`È!¬°q¸*×)EÑ(`ùr„  c                ó°   •— t        | t        «      xrD t        ˆfd„| j                  d«      xs g D «       «      xs t	        | j                  d«      ‰«      S )Nc              3  ó6   •K  — | ]  }t        |‰«      –— Œ y ­wrl  r  r  s     €rÔ   rp  zG_config_selects_provider.<locals>._moa_block_matches.<locals>.<genexpr>O  s   øè ø€ ÒZ°”˜a ×,ÑZùr„  Úreference_modelsÚ
aggregator)rm  ró   r¿  r¾  r  )Úblockr®  s    €rÔ   Ú_moa_block_matchesz4_config_selects_provider.<locals>._moa_block_matchesM  sP   ø€ Ü˜%¤Ó&ò CÜÓZ°e·i±iÐ@RÓ6SÒ6YÐWYÔZÓZò BÜ˜UŸY™Y |Ó4°jÓAð	Crô   r³  FÚpresetsrê   c              3  ó.   •K  — | ]  } ‰|«      –— Œ y ­wrl  rê   )rn  r»  r  s     €rÔ   rp  z+_config_selects_provider.<locals>.<genexpr>W  s   øè ø€ Ò-UÈÑ.@À×.CÑ-Uùs   ƒ)r  r   Úreturnrª  )r…  rÉ  r  r¾  rm  ró   r¿  Úvalues)r®  rÉ  ÚcfgÚaux_cfgÚmoa_cfgr  r  s   `     @rÔ   Ú_config_selects_providerr"  <  s¸   ù€ õ .Ù
‹-€CÜ�S—W‘W˜WÓ% zÔ2Øð �g‰g�kÓ"€GÜ�'œ4Ô ¤SÓ(`ÈwÏ~É~ÓO_Ô(`Ô%`ØõCð
 �g‰g�e‹n€GÜ�gœtÔ$ØØ�k‰k˜)Ó$€GÜ",¨W´dÔ";ˆg�n‰nÔÀ€GÙ˜gÓ&ÒU¬#Ó-UÈWÔ-UÓ*UÐUrô   c                ó8   — t        d„ t        | «      D «       «      S )z²Pool rows from EXPLICIT Hermes flows (manual add / device-code / PKCE) or live env keys;
    ambient borrowed sources (gh_cli / claude_code / qwen-cli) are deliberately excluded.c              3  ó2   K  — | ]  }t        |«      –— Œ y ­wrl  )Ú_pool_entry_is_explicit)rn  ré  s     rÔ   rp  z/_explicit_pool_entry_present.<locals>.<genexpr>]  s   è ø€ Ò\°%Ô& u×-Ñ\ùs   ‚)r¿  rÃ  )r®  s    rÔ   Ú_explicit_pool_entry_presentr&  Z  s   € ô Ñ\Ô;OÐPZÓ;[Ô\Ó\Ð\rô   r3  >   ÚmanualÚdevice_codeÚhermes_pkceÚloopback_pkce)rf  zgoogle-vertexz	vertex-aiz
gcp-vertexÚvertexaic                ó8   — ddl m} t         || «      xs d«      S )uÞ  True when *name* resolves to a usable secret in the active profile scope.

    Must not read raw ``os.getenv``: under ``hermes serve`` / Desktop multiplex the
    process environ is the *launch* profile, so a DeepSeek key pasted into another
    profile's ``.env`` would be invisible to ``explicit_only`` Settings â†’ Model
    until a Bot-chat Refresh ran against that profile's own backend.
    Same reader as the credential resolver (``get_env_value_prefer_dotenv``: the current
    HERMES_HOME ``.env`` first, then the scope-checked environ) so the gate and the key that
    actually authenticates never disagree â€” an empty ``DEEPSEEK_API_KEY=`` export in the parent
    shell must not hide a real key in ``.env`` (#77007).
    r   r{  rÈ   )r…  r|  r¶  )rá   r|  s     rÔ   Ú_env_secretr-  f  s   € õ >ÜÑ8¸Ó>ÒDÀ"ÓEÐErô   c                ó  — t         j                  | «      }|€ddlm}  || «      }|sy|j                  dk(  rt        d„ |j                  D «       «      S |j                  dk(  r%t        d«      xs t        d«      xr t        d	«      S y)
uK  True when the user has pasted an explicit credential env var for *normalized*.

    Falls back to the models.dev ``ProviderDef`` (same shape) for non-registry providers such as
    openrouter. AWS SDK providers are checked via explicit env vars only â€” NOT boto3's chain, so
    ambient EC2 IMDS / SSO profiles never auto-surface.r   )Úget_providerFÚapi_keyc              3  óD   K  — | ]  }|t         vsŒt        |«      –— Œ y ­wrl  )Ú_IMPLICIT_ENV_VARSr-  r~  s     rÔ   rp  z4_explicit_env_credentials_present.<locals>.<genexpr>ƒ  s   è ø€ Òc aÀqÔPbÒGb”;˜q—>Ñcùs   ‚ � re  ÚAWS_BEARER_TOKEN_BEDROCKÚAWS_ACCESS_KEY_IDÚAWS_SECRET_ACCESS_KEY)rq  r¾  Úhermes_cli.providersr/  râ   r¿  rì   r-  )r®  rá  r/  s      rÔ   Ú!_explicit_env_credentials_presentr7  v  s‹   € ô  ×#Ñ# JÓ/€GØ€Ý5Ù˜zÓ*ˆÙØØ×Ñ˜IÒ%ÜÑc¨7×+CÑ+CÔcÓcÐcØ×Ñ˜IÒ%ÜÐ5Ó6ò WÜÐ+Ó,ÒU´Ð=TÓ1Uð	Wàrô   c                ó   — t        | t        «      syt        | j                  d«      xs d«      j	                  «       j                  «       }|j                  d«      rK| j                  dd«      j                  dd«      d   j	                  «       }t        |xr t        |«      «      S t        |«      xr |t        v xs |j                  d«      S )zZTrue for pool rows the user created via an explicit Hermes flow (or a still-live env key).FrÄ  rÈ   zenv:ú:r8  zmanual:)rm  ró   rØ   r¾  rÙ   rÏ   r¤  r  rª  r-  Ú_EXPLICIT_POOL_SOURCES)ré  rÄ  ræ  s      rÔ   r%  r%  Š  s¯   € ä�eœTÔ"ØÜ�—‘˜8Ó$Ò*¨Ó+×1Ñ1Ó3×9Ñ9Ó;€FØ×Ñ˜Ô ð —)‘)˜H bÓ)×/Ñ/°°QÓ7¸Ñ:×@Ñ@ÓBˆÜ�GÒ4¤¨GÓ 4Ó5Ð5Ü�‹<Ò^˜VÔ'=Ð=Ò]À×ARÑARÐS\ÓA]Ð^rô   c                ó  — | t         v rddlm} t         |«       «      S | dk(  rcddlm}  |«       j                  d«      }t        |t        «      xr5 t        t        |j                  d«      xs d«      j                  «       «      S y)ax  Vertex / Bedrock count as explicit when Hermes-scoped routing config is present.

    Uses has_explicit_vertex_config(), NOT has_vertex_credentials(): the latter also counts an
    ambient GOOGLE_APPLICATION_CREDENTIALS path (commonly set for unrelated GCP work). Only
    Hermes-scoped signals (VERTEX_PROJECT_ID / vertex.project_id / VERTEX_CREDENTIALS_PATH) count
    here.r   )Úhas_explicit_vertex_configrc  rÈ  r,  rÈ   F)Ú_VERTEX_PROVIDER_IDSÚagent.vertex_adapterr<  rª  r…  rÉ  r¾  rm  ró   rØ   rÙ   )r®  r<  rÉ  Úbedrock_cfgs       rÔ   Ú%_keyless_provider_has_explicit_configr@  ˜  ss   € ð Ô)Ñ)ÝCÜÑ.Ó0Ó1Ð1Ø�YÒÝ1Ù!“m×'Ñ'¨	Ó2ˆÜ˜+¤tÓ,Òc´´c¸+¿/¹/È(Ó:SÒ:YÐWYÓ6Z×6`Ñ6`Ó6bÓ1cÐcØrô   z.Tuple[Tuple[Callable[[str], bool], bool], ...]Ú_EXPLICIT_CONFIG_CHECKSc                óð   — | xs dj                  «       j                  «       }t        D ]  \  }}	  ||«      r yŒ y# t        $ r/}|s‚ t        j                  d|j                  | |«       Y d}~ŒGd}~ww xY w)ar  True only if the user explicitly configured this provider: auth.json ``active_provider``,
    config.yaml ``model.provider`` / MoA slots, a pasted provider env var, a pool entry from a
    Hermes-initiated flow, or Hermes-scoped routing config for keyless cloud-SDK providers. Ambient
    borrowed credentials (gh CLI, qwen-cli, ~/.claude/.credentials.json) never count.rÈ   Tz*explicit-config check %s failed for %s: %sNF)rÙ   rÏ   rA  rÑ   rÀ  rw  rî   )rÃ  r®  ÚcheckÚbest_effortrå  s        rÔ   Ú!is_provider_explicitly_configuredrE  ²  s‡   € ð
 Ò# ×*Ñ*Ó,×2Ñ2Ó4€JÜ5ò iÑˆˆ{ð	iÙ�ZÔ Ùð !ðið øô	 ò 	iÙØÜ�L‰LÐEÀuÇ~Á~ÐWbÐdg×hÑhûð	iús   °=½	A5Á%A0Á0A5c                ó*  — t        «       5  t        «       }| xs |j                  d«      }|s
	 ddd«       yd}dD ]  }t        ||«      }||v sŒ||= d}Œ |j                  d«      |k(  rd|d<   d}|rt	        |«       |cddd«       S # 1 sw Y   yxY w)z’Clear auth state for a provider (the active one when *provider_id* is None). Used by
    ``hermes logout``. Returns True if something was cleared.rq  NF)rj  rn  T)rg  r  r¾  r�  r‹  )rÃ  rŠ  r�  ÚclearedrŽ  rÞ  s         rÔ   Úclear_provider_authrH  Ã  s³   € ô 
Ó	ñ Ü%Ó'ˆ
ØÒA 
§¡Ð/@Ó AˆÙØ÷	ð ð
 ˆØ7ò 	ˆGÜ$ Z°Ó9ˆGØ˜Ò Ø˜F�OØ‘ð		ð
 �>‰>Ð+Ó,°Ò6Ø,0ˆJÐ(Ñ)ØˆGÙÜ˜ZÔ(Ø÷!÷ ò ús   ‹#B	·B	Á0B	Â	Bc                 óv   — t        «       5  t        «       } d| d<   t        | «       ddd«       y# 1 sw Y   yxY w)z¼Clear active_provider without deleting credentials: used when the user switches to a non-OAuth
    provider (OpenRouter, custom) so auto-resolution doesn't keep picking the OAuth provider.Nrq  )rg  r  r‹  )rŠ  s    rÔ   Údeactivate_providerrJ  Ù  s:   € ô 
Ó	ñ %Ü%Ó'ˆ
Ø(,ˆ
Ð$Ñ%Ü˜Ô$÷%÷ %ñ %ús   ‹/¯8c                óì  — t        | xs d«      j                  «       j                  «       dv ry	 ddlm}  |«       }|sydg}|D ]Ž  }|j                  d|j                  dk(  rd	nd
› d|j                  › �«       |j                  sŒB|j                  j                  «       d   sŒ`|j                  d|j                  j                  «       d   › �«       Œ� dj                  |«      S # t        $ r Y yw xY w)z<Return a helpful hint string when provider resolution fails.rÈ   >   úopencode-freeÚfreeÚopencode_freea'  OpenCode discontinued anonymous free-tier access outside its own client (relay 403s FreeTierError), so the keyless 'opencode-free' provider was removed. Switch to 'opencode-zen' (pay-as-you-go, OPENCODE_ZEN_API_KEY) or 'opencode-go' ($10/mo subscription, OPENCODE_GO_API_KEY) via 'hermes model'.r   )Úvalidate_config_structureuC   Config issue detected â€” run 'hermes doctor' for full diagnostics:z  [rñ  ÚERRORÚWARNINGz] u       â†’ ú
)rØ   rÙ   rÏ   r…  rO  rß  ÚseverityÚmessageÚhintÚ
splitlinesrÂ  rÑ   )Úprovider_namerO  ÚissuesÚlinesÚcis        rÔ   Ú%_get_config_hint_for_unknown_providerr[  å  sð   € ä
ˆ=Ò˜BÓ×%Ñ%Ó'×-Ñ-Ó/Ð3]Ñ]ðQðÝ?Ù*Ó,ˆÙØØVÐWˆØò 	CˆBØ�L‰L˜3¨"¯+©+¸Ò*@™wÀiÐPÐPRÐSU×S]ÑS]ÐR^Ð_Ô`Ø�w‹w˜2Ÿ7™7×-Ñ-Ó/°Ó2Ø—‘˜x¨¯©×(:Ñ(:Ó(<¸QÑ(?Ð'@ÐAÕBð	Cð �y‰y˜ÓÐøÜò Ùðús%   °C' Á AC' ÂC' Â%AC' Ã'	C3Ã2C3c                 ó¸   — 	 ddl m}   | «       }|syt        «       }t        d|› d|› d�d¬	«      ‚# t        $ r }t        j                  d|«       Y d}~yd}~ww xY w)
a[  Refuse env-key/pool auto-adoption of openrouter while config.yaml is corrupt.

    A corrupt config loads as ``DEFAULT_CONFIG`` (no ``model.provider``), so the env sniff would
    silently adopt the PAID openrouter provider over whatever the broken config really names.
    Fires ONLY on the auto path and clears itself once the file parses again.r   )Úget_active_config_parse_failureNz.Could not probe config parse-failure state: %szconfig.yaml at z is corrupt (uŒ   ) â€” refusing to auto-select an inference provider from environment keys. Fix the YAML (a backup was saved next to it) or run hermes setup.Úcorrupt_config©rï  )r…  r]  rt  rÑ   rÀ  rw  rÄ   )r]  ÚerrrÚ   rã  s       rÔ   Ú&_refuse_env_adoption_if_config_corruptra  û  so   € ðÝEÙ-Ó/ˆÙØÜÓ ˆô Ø
˜$˜˜}¨S¨Eð 25ð 	6ð ô	ð øô ò Ü�‰ÐEÀqÔIÜûðús   ‚0 ’
0 °	A¹AÁAÚglmr  zz-aizz.aiÚzhipuÚgoogler
  zgoogle-geminizgoogle-ai-studiozx-airB  zx.aiÚgrokz
x-ai-oauthz
grok-oauthzxai-grok-oauthÚkimir  zkimi-for-codingÚmoonshotzkimi-cnr  zmoonshot-cnÚstepzstepfun-coding-planzarcee-air  Úarceeaiz	gmi-cloudr  Úgmicloudzactual-computerÚactualcomputerÚacizminimax-chinar;  Ú
minimax_cnzminimax-portalzminimax-globalÚminimax_oauthÚalibaba_codingr8  zalibaba-codingÚalibaba_coding_planÚclauder/  zclaude-codeÚgithubzgithub-copilotzgithub-modelszgithub-modelzgithub-copilot-acpzcopilot-acp-agentÚ	aigatewayrI  Úvercelzvercel-ai-gatewayÚopencoderL  Úzenzqwen-portalzqwen-cliÚhfrU  zhugging-facezhuggingface-hubÚmimorX  zxiaomi-mimoÚtencentr[  Útokenhubztencent-cloudÚtencentmaasÚ	tokenplanr^  ztencent-lkeapÚawsrc  zaws-bedrockzamazon-bedrockÚamazonÚgorO  rR  rÿ   rµ  )zopencode-go-subÚkiloz	kilo-codezkilo-gatewayrÿ   z	lm-studioÚ	lm_studioÚchatgptzchatgpt-codexÚollamaÚollama_cloudÚvllmÚllamacppz	llama.cppz	llama-cppúDict[str, str]Ú_PROVIDER_ALIASESc                 óÆ   — t        t        «      } 	 ddlm}  |«       D ]/  }|j                  D ]  }| j                  ||j                  «       Œ  Œ1 	 | S # t        $ r Y | S w xY w)zX``_PROVIDER_ALIASES`` extended with aliases declared in plugins/model-providers/<name>/.r   )Úlist_providers)ró   rˆ  rj  rŠ  Úaliasesr1  rá   rÑ   )r‹  Ú_lpÚ_ppÚ_aliass       rÔ   Ú_plugin_aliasesr�  ;  sm   € äÔ$Ó%€GðÝ3Ù“5ò 	5ˆCØŸ+™+ò 5�Ø×"Ñ" 6¨3¯8©8Õ4ñ5ñ	5ð
 €Nøô ò ØØ€Nðús   ‘?A Á	A ÁA c                 ód   — 	 ddl m}  | S # t        $ r t        j	                  dd«       d„ cY S w xY w)a,  Scope-aware key reader for provider auto-detection.

    Under multiplex a secondary profile's keys live only in its secret scope, not os.environ. Catch
    ONLY ImportError: any other auxiliary_client failure must propagate rather than silently
    falling back to os.getenv (a traceless fail-open).r   ©Ú_scoped_key_envu·   agent.auxiliary_client unavailable (%s); provider auto-detection will read keys from the process environment only â€” under multiplex, secondary profiles may report 'No LLM provider'.zimport failedc                ó4   — t        j                  | «      xs dS r«  )r	  Úgetenv)rá   s    rÔ   ú<lambda>z(_scoped_key_env_reader.<locals>.<lambda>Z  s   € œBŸI™I d›OÒ1¨r€ rô   )Úagent.auxiliary_clientr’  ÚImportErrorrÀ  rÁ  r‘  s    rÔ   Ú_scoped_key_env_readerr˜  H  s@   € ð2õ 	;ØÐøÜò 2Ü�‰ðJð ô		ñ
 2Ò1ð2ús   ‚
 Š"/®/c                óÒ   ‡ — t        ˆ fd„dD «       «      ry	 ddlm} t         |d«      j	                  «       «      S # t
        $ r }t        j                  d|«       Y d}~y	d}~ww xY w)
zþTrue when an OpenRouter credential exists via env key or the credential pool (a key added via
    `hermes auth add openrouter` has no env var; without the pool check it is invisible to
    auto-detection and requests go out with no Authorization header).c              3  ó@   •K  — | ]  }t         ‰|«      «      –— Œ y ­wrl  )r¶  )rn  r  Úscoped_key_envs     €rÔ   rp  z,_openrouter_auto_detected.<locals>.<genexpr>a  s   øè ø€ Ò
b°AÔ™^¨AÓ.×/Ñ
bùr½  )rû   ÚOPENROUTER_API_KEYTr   rÔ  r·  z.Could not check OpenRouter credential pool: %sNF)r¿  rÛ  rÕ  rª  rÜ  rÑ   rÀ  rw  )r›  Ú
_load_poolrã  s   `  rÔ   Ú_openrouter_auto_detectedrž  ]  s]   ø€ ô Ó
bÐ9aÔ
bÔbØð
õ 	BÜ‘J˜|Ó,×<Ñ<Ó>Ó?Ð?øÜò Ü�‰ÐEÀqÔIÜûðús   ˜$= ½	A&ÁA!Á!A&©Úskip_free_tierc                ó  — 	 t        «       j                  d«      }|dk(  rddlm}m}  |«       r
| s |«       sy|r$|t
        v rt        |«      j                  d«      r|S y# t        $ r }t        j                  d|«       Y d}~yd}~ww xY w)zTauth.json ``active_provider`` when it is a registry provider that reports logged in.rq  r÷   r   ©Úguest_enabledÚ	has_guestNÚ	logged_inz+Could not pre-read active auth provider: %s)
r  r¾  Úhermes_cli.anon_authr£  r¤  rq  Úget_auth_statusrÑ   rÀ  rw  )r   Ú_mayber£  r¤  rã  s        rÔ   Ú _logged_in_oauth_active_providerr©  p  s†   € ð	GÜ!Ó#×'Ñ'Ð(9Ó:ˆØ�VÒßEÙŒ{¡±m´oØÙ�fÔ 1Ñ1´oÀfÓ6M×6QÑ6QÐR]Ô6^ØˆMð øô ò GÜ�‰ÐBÀA×FÐFØûðGús   ‚6A  ¹%A  Á 	B	Á)BÂB	c                 ó¢  — 	 ddl m}   | «       xs i j                  d«      }t        |t        «      r|j                  d«      nd}t        |t
        «      r|j                  «       j                  «       nd}t        «       j                  ||«      }|dk(  s|j                  d«      r|dfS |d	k(  s|t        v r||fS |rdd
lm}  ||«      r|dfS t        |t        «      r,t        |j                  d«      xs d«      j                  «       nd}|rddlm}  |||«      r|dfS |dfS # t        $ r }t         j#                  d|«       Y d}~yd}~ww xY w)a  ``(model_cfg, provider)`` from config.yaml when ``model.provider`` names a registry provider
    or a custom OpenAI-compatible endpoint (``custom``, ``custom:<name>``, ``vllm``/``ollama``/...).
    A ``model.provider: openrouter`` pin and a bare ``providers:`` entry name are explicit intent too.

    The normal chat/gateway path resolves config.provider upstream in resolve_requested_provider();
    this is the safety net for the direct ``resolve_provider("auto")`` callers. A configured custom
    endpoint is explicit intent like any registry pin: without this rung the boot inventory
    (``free_tier_bootstrap``) read a llama.cpp/vLLM install as "nothing configured" and the
    dashboard's Ink chat parked every session on Setup Required while ``hermes chat`` worked
    (#108383).r   rÈ  rÊ  rË  NrÈ   rµ  r¶  r·  )Úhas_named_custom_providerrÒ   )Ú,_config_base_url_trustworthy_for_bare_customzACould not read config.yaml model.provider for auto-resolution: %sr”  )r…  rÉ  r¾  rm  ró   rØ   rÙ   rÏ   r�  r¤  rq  Ú"hermes_cli.runtime_provider_customr«  Úhermes_cli.runtime_providerr¬  rÑ   rÀ  rw  )rÉ  rÎ  rË  r«  rÒ   r¬  rã  s          rÔ   Ú_config_model_providerr¯    sB  € ðÝ1Ù “]Ò( b×-Ñ-¨gÓ6ˆ	Ü0:¸9ÄdÔ0K�9—=‘= Ô,ÐQUˆÜ/9¸(ÄCÔ/H�8—>‘>Ó#×)Ñ)Ô+ÈbˆÜ"Ó$×(Ñ(¨°8Ó<ˆØ�xÒ 8×#6Ñ#6°yÔ#AØ˜hÐ&Ð&ð �|Ò# xÔ3DÑ'DØ˜hÐ&Ð&ñ ÝTÙ(¨Ô2Ø  (Ð*Ð*ô DNÈiÔY]ÔC^”3�y—}‘} ZÓ0Ò6°BÓ7×=Ñ=Ô?ÐdfˆÙÝ`Ù;¸HÀhÔOØ  (Ð*Ð*Ø˜$ˆÐøÜò Ü�‰ÐXÐZ[Ô\Üûðús1   ‚B&D% Â)D% Â:D% ÃAD% Ä!D% Ä%	EÄ.E	Å	Ec           	     óü   — t         j                  «       D ]e  \  }}|j                  dk7  s|t        v rŒ|j                  D ]9  }t         | |«      «      sŒ|r||k7  rt        j                  d||||«       |c c S  Œg y)z¹First registry api_key provider (registry order) with a usable env key, warning when it
    preempts a logged-in OAuth provider so a stale key in ~/.hermes/.env never switches silently.r0  zžProvider resolved to %r via %s, preempting your logged-in OAuth provider %r. If you meant to use the OAuth login, unset %s or set `model.provider` explicitly.N)rq  rº  râ   Ú_NO_AUTO_DETECT_PROVIDERSrì   r¶  rÀ  rÁ  )r›  Úoauth_activeÚpidrá  ræ  s        rÔ   Ú_env_key_auto_detectedr´  °  s�   € ô *×/Ñ/Ó1ò ‰ˆˆWØ×Ñ 	Ò)¨SÔ4MÑ-MØØ×/Ñ/ò 	ˆGÜ ¡°Ó!8Õ9Ù L°CÒ$7Ü—N‘Nð&ð ˜W l°Gô=ð ”
ñ	ðð  rô   )Úexplicit_api_keyÚexplicit_base_urlr   c               ó  — | xs dj                  «       j                  «       }t        «       j                  ||«      }|dv st	        |«      �|S |dk7  r(t        |«      }|rd|› �nd}t        d|› d�|z   d¬	«      ‚|s|ry
t        «       \  }}|r|S t        «       }	t        |	«      rt        «        y
t        |¬«      }
t        |	|
«      }|r|S |
r;t        |t        «      r)|r'|j                  d«      st        j!                  d|
«       |
S |s	 ddlm}m}  |«       r |«       ry	 ddlm}  |«       ry	 ddlm} t        d |«       › d�d¬	«      ‚# t(        $ r }t        j+                  d|«       Y d}~ŒPd}~ww xY w# t0        $ r Y ŒSw xY w)aM  Determine which inference provider to use.

    "auto" priority (explicit intent beats a stale OAuth login): 1. CLI api_key/base_url ->
    "openrouter"; 2. config.yaml ``model.provider``; 3. OPENAI_API_KEY / OPENROUTER_API_KEY ->
    "openrouter"; 4. OpenRouter pool; 5. provider env keys; 6. auth.json ``active_provider``;
    7. Nous free tier when it is on and its identity exists (never created here);
    8. AWS Bedrock chain; 9. AuthError(no_provider_configured).

    ``skip_free_tier`` hides rungs 6-for-a-free-tier-identity and 7: the boot bootstrap asks
    "what would carry inference if the free tier did not exist?" to decide whether a fresh identity
    may become ``active_provider``.

    1. 3. 4. 5. Provider-specific API keys (GLM, Kimi, MiniMax, ...) -> that provider 7. 8. Error (no
    provider configured) See #29285.
    r´  )r·  rµ  Nz

z` Check 'hermes model' for available providers, or run 'hermes doctor' to diagnose config issues.zUnknown provider 'z'.Úinvalid_providerr_  r·  rŸ  rË  z§Provider resolved to logged-in OAuth provider %r because config.yaml `model` has no `provider` key. If you meant a different provider, set `model.provider` explicitly.r   r¢  r÷   z6free tier check during provider resolution skipped: %s©Úhas_aws_credentialsrc  )Údisplay_hermes_homezõHermes is not connected to any AI provider yet. Run `hermes model` to pick one (the free Nous tier needs no API key), type `/login` in chat, or add a key with `hermes auth add <provider>`. (Advanced: put an API key such as OPENROUTER_API_KEY in z/.env.)Úno_provider_configured)rÙ   rÏ   r�  r¾  r¬  r[  rÄ   r¯  r˜  rž  ra  r©  r´  rm  ró   rÀ  rÁ  r¦  r£  r¤  rÑ   rw  Úagent.bedrock_adapterrº  r—  rþ  r»  )Ú	requestedrµ  r¶  r   r®  rU  r®  Ú
_model_cfgÚcfg_providerr’  Ú_oauth_activeÚenv_pidr£  r¤  rå  rº  r»  s                    rÔ   r·  r·  Ç  s½  € ð* Ò%˜v×,Ñ,Ó.×4Ñ4Ó6€JÜ Ó"×&Ñ& z°:Ó>€JàÐ-Ñ-Ô1AÀ*Ó1MÐ1YØÐØ�VÒÜ4°ZÓ@ˆÙ!%�$�t�f‘ð ,DˆäÐ,¨Z¨L¸Ð;¸dÑBÐI[Ô\Ð\áÑ,Øä5Ó7Ñ€J�ÙØÐä,Ó.€OÜ  Ô1Ü.Ô0Øô 5ÀNÔS€MÜ$ _°mÓD€GÙØˆñ Ü�j¤$Ô'©J¸z¿~¹~ÈjÔ?YÜ�N‰NðGð ô	ð
 Ðñ ð	XßEÙŒ¡9¤;Øð
Ý=ÙÔ Øð !õ 5Ü
ð	añ Ó Ð
! ð	*ð &ô'ð 'øô ò 	XÜ�L‰LÐQÐSV×WÑWûð	Xûô ò Ùðús*   ÄE Ä%E< Å	E9ÅE4Å4E9Å<	FÆFc                 ó„   — t        j                  t        j                  «      j	                  «       j                  dd«      S )zQCurrent UTC time as an ISO-8601 string with a ``Z`` suffix (last_refresh format).ú+00:00ÚZ)r	   r‡  r
   rˆ  r‰  r©  rê   rô   rÔ   Ú
_utc_now_zrÆ  '  s+   € ä�<‰<œŸ™Ó%×/Ñ/Ó1×9Ñ9¸(ÀCÓHÐHrô   c                ó@  — t        | t        «      r| j                  «       nd}|sy |j                  d«      r|d d dz   }	 t	        j
                  |«      }|j                  € |j                  t        j                  ¬«      }|j                  «       S # t        $ r Y y w xY w)NrÈ   rÅ  éÿÿÿÿrÄ  )Útzinfo)rm  rØ   rÙ   r¥  r	   ÚfromisoformatrÑ   rÉ  r©  r
   rˆ  Ú	timestamp)r«  ÚtextrÜ   s      rÔ   Ú_parse_iso_timestamprÍ  ,  s’   € Ü& u¬cÔ2ˆ5�;‰;Œ=¸€DÙØØ‡}�}�SÔØ�C�Rˆy˜8Ñ#ˆðÜ×'Ñ'¨Ó-ˆð ‡}�}ÐØ—‘¤x§|¡|�Ó4ˆØ×ÑÓÐøô	 ò Ùðús   Á B Â	BÂBc                óX   — t        | «      }|d u xs |t        j                  «       |z   k  S rl  )rÍ  rV  )Úexpires_at_isoÚskew_secondsÚexpires_epochs      rÔ   Ú_is_expiringrÒ  ;  s,   € Ü(¨Ó8€MØ˜DÐ ÒQ M´d·i±i³kÀLÑ6PÑ$QÐQrô   c                ó8   — | du t        | t        «      r| dœS ddœS )zAPersistable ``tls`` block derived from an httpx ``verify`` value.FN)ÚinsecureÚ	ca_bundle)rm  rØ   )Úverifys    rÔ   Ú_tls_state_from_verifyr×  @  s$   € à %˜Ä
È6ÔSVÔ@W°fÑbÐbÐ]aÑbÐbrô   )Údefault_codec               ó¼   — | t        |«      |d|€|j                  n|j                  xs |t        j                  t        j
                  «      j                  «       dœS )zQThe ``last_auth_error`` record persisted when dead OAuth material is quarantined.T)rË  rT  Úreasonrî  rï  Úat)rØ   rï  r	   r‡  r
   rˆ  r‰  )rË  rñ  rÚ  rØ  s       rÔ   Ú_last_auth_error_markerrÜ  E  sL   € ð
 ¬¨U«¸vÐ[_Ø*Ð2�—
’
¸¿¹Ò9SÀ|Ü�l‰lœ8Ÿ<™<Ó(×2Ñ2Ó4ñ6ð 6rô   )r×  Úrefresh_tokenÚ
expires_atÚ
expires_inÚobtained_atc                ób   — t         D ]  }| j                  |d«       Œ t        ||dd¬«      | d<   y)z¶Strip dead tokens from a flat OAuth state after a terminal runtime refresh failure so
    subsequent calls fail fast without a network retry (mirrors the Nous / xAI / Codex pattern).NÚruntime_refresh_failureÚrefresh_failed)rÚ  rØ  Úlast_auth_error)Ú_FLAT_OAUTH_TOKEN_KEYSr   rÜ  )r‘  rË  rå  Ú_ks       rÔ   Ú_quarantine_flat_oauth_staterç  R  s=   € ô %ò ˆØ�	‰	�"�dÕðä6Ø�#Ð7ÐFVô X€EÐ
Òrô   c                óL   — 	 t        dt        | «      «      S # t        $ r Y yw xY w)Nr   )rX  ÚintrÑ   )rß  s    rÔ   Ú_coerce_ttl_secondsrê  [  s*   € ðÜ�1”c˜*“oÓ&Ð&øÜò Ùðús   ‚ —	#¢#c                óp   — t        | t        «      r| j                  «       j                  d«      nd}|xs d S )Nr×   rÈ   )rm  rØ   rÙ   rÐ   )r«  rµ  s     rÔ   Ú_optional_base_urlrì  b  s-   € Ü+5°e¼SÔ+Aˆe�k‰k‹m×"Ñ" 3Ô'Àr€GØŠ?�dÐrô   >   úportal.nousresearch.comrÌ   rÍ   úFrozenSet[str]Ú_NOUS_PORTAL_ALLOWED_HOSTSz'dict[str, tuple[float, str]]'Ú_RESOLVE_TOKEN_CACHEç      @c                ó  — t        «       }|r|j                  d«      S t        | j                  d«      «      xs t        }|j                  d«      }t        |«      j                  }|r%|t        vrt        j                  d||«       t        S |S )a  HERMES_PORTAL_BASE_URL / NOUS_PORTAL_BASE_URL is the trusted operator override and wins
    OUTRIGHT, bypassing the host allowlist (which exists to reject an untrusted network-provided
    value, not one the operator configured). Otherwise the stored/default value, allowlist-gated.r×   rã   zSauth: ignoring invalid portal_base_url %r (host %r not in allowlist), using default)
rJ   rÐ   rì  r¾  r›   r   rÎ   rï  rÀ  rÁ  )r‘  Úenv_portal_overriderã   rÓ   s       rÔ   Ú_nous_portal_base_urlrô  w  sˆ   € ô 4Ó5ÐÙØ"×)Ñ)¨#Ó.Ð.Ü(¨¯©Ð3DÓ)EÓFÒaÔJa€OØ%×,Ñ,¨SÓ1€OÜ�OÓ$×-Ñ-€DÙ�Ô6Ñ6Ü�‰ØaØ˜Tô	#ô 'Ð&ØÐrô   ç      .@)r_  rÔ  rÕ  Úrefresh_skew_secondsc                ó¼  ‡‡‡‡‡— | xr |du Št        «       Š‰rLt        5  t        j                  ‰«      }ddd«       �&t	        j
                  «       |d   z
  t        k  r|d   S dˆˆfd„}t        d«      5 \  ŠŠŠ‰st        ddd¬	«      ‚t        ‰«      }t        ‰j                  d
«      xs t        «      }t        ||‰¬«      }ˆˆˆfd„}	t        | dz   t        «      }
t        |
¬«      5  ddlm}m}  |‰«      rÊ‰j                  d«      }t'        |t        «      r7|r5t)        ‰j                  d«      |«      s ||«      cddd«       cddd«       S t+        j,                  t+        j.                  | xs d«      ddi|¬«      5 } |‰|«       ddd«        |	«        t1        ‰«        |‰d   «      cddd«       cddd«       S t3        ‰«      }‰j                  d«      }‰j                  d«      }t'        |t        «      r|st        ddd¬	«      ‚t)        ‰j                  d«      |«      s#|r |	«         ||«      cddd«       cddd«       S t'        |t        «      r|st        ddd¬	«      ‚t+        j,                  t+        j.                  | xs d«      ddi|¬«      5 }t5        |‰‰|||d|	¬«      }ddd«       t7        ‰|«       |‰d<   |‰d
<   t9        |«      ‰d<    |	«        t1        ‰«        |‰d   «      cddd«       cddd«       S # 1 sw Y   �ŒáxY w# 1 sw Y   �Œ’xY w# 1 sw Y   ŒwxY w# 1 sw Y   nxY w	 ddd«       y# 1 sw Y   yxY w) zKResolve a refresh-aware Nous Portal access token for managed tool gateways.Nr   r8  c                ó‚   •— ‰r.t         5  t        j                  «       | ft        ‰<   d d d «       | S | S # 1 sw Y   | S xY wrl  )Ú_RESOLVE_TOKEN_CACHE_LOCKrV  rW  rð  )râ  r  Úmemoables    €€rÔ   Ú_memoz(resolve_nous_access_token.<locals>._memo™  sA   ø€ ÙÜ*ñ LÜ37·>±>Ó3CÀUÐ2KÔ$ YÑ/÷Làˆˆuˆ÷Làˆús   Š4´>r÷   z&Hermes is not logged into Nous Portal.Únous_auth_missingT)Úreloginrå   )rÔ  rÕ  Ú
auth_statec                 ó    •— t        ‰ d‰‰«      S )Nr÷   )r§  )rŠ  r‘  Ústate_source_paths   €€€rÔ   r•  z+resolve_nous_access_token.<locals>.<lambda>¥  s   ø€ Ô8Ø˜ Ð'8ó:€ rô   rñ  )r_  )Úis_guest_stateÚrefresh_guest_stater×  rÞ  rõ  ÚAcceptzapplication/json)ÚtimeoutÚheadersrÖ  rÝ  z,No access token found for Nous Portal login.Únous_auth_missing_access_tokenz2Session expired and no refresh token is available.Únous_auth_missing_refresh_tokenÚ$managed_access_token_refresh_failure)ÚclientrŠ  r‘  rã   rå   rÝ  rÚ  Úpersistrã   Útls)râ  rØ   r  rØ   )r   rù  rð  r¾  rV  rW  Ú_RESOLVE_TOKEN_CACHE_TTL_Sr›  rÅ   rô  rØ   r�   r1   rX  rš   rK   r¦  r  r  rm  rÒ  rÆ   ÚClientÚTimeoutrX   rD   rR   r>   r×  )r_  rÔ  rÕ  rö  r   rû  rã   rå   rÖ  r
  Úlock_timeoutr  r  r×  r	  Úmerged_sharedrÝ  Ú	refreshedrŠ  r  rú  r‘  r   s                     @@@@@rÔ   Úresolve_nous_access_tokenr  ‰  si  ü€ ð ˆ|Ò1 	¨TÐ 1€HÜÓ!€IÙÜ&ñ 	9Ü)×-Ñ-¨iÓ8ˆF÷	9àÐ¤4§>¡>Ó#3°f¸Q±iÑ#?ÔC]Ò"]Ø˜!‘9Ðöô 
% VÓ	,ð ;0Ñ0V°¸UÐDUÙÜÐDÐFYÐcgÔhÐhÜ/°Ó6ˆÜ˜Ÿ	™	 +Ó.ÒHÔ2HÓIˆ	Ü ¨(¸iÐTYÔZˆõ:ˆô ˜?¨SÑ0Ô2KÓLˆÜ$°\ÔBñ 1	0ßPÙ˜eÔ$ð  %Ÿy™y¨Ó8�Ü˜l¬CÔ0±\Ì,ØŸ	™	 ,Ó/Ð1EôKGá  Ó.÷1	0ð 1	0÷;0ñ ;0ô& —\‘\¬%¯-©-¸Ò8OÈ4Ó*PØ+3Ð5GÐ*HÐQWôYð 7Ø\bÙ'¨¨vÔ6÷7ñ ”	Ü(¨Ô/Ù˜U >Ñ2Ó3÷1	0ð 1	0÷;0ñ ;0ô4 ;¸5ÓAˆMØ Ÿ9™9 ^Ó4ˆLØ!ŸI™I oÓ6ˆMÜ˜l¬CÔ0¹ÜØBÐDdÐnrôtð tô   §	¡	¨,Ó 7Ð9MÔNÙ Ù”Iñ ˜\Ó*÷;1	0ð 1	0÷;0ñ ;0ôR ˜m¬SÔ1¹ÜØHÐJkØ ô"ð "ô —‘¤e§m¡m°OÒ4KÀtÓ&LØ'/Ð1CÐ&DÈVôUð TØX^Ü7Ø!¨jÀÐWfØ'°}ØAÈ7ôT�	÷Tô )¨°	¸=ÔIØ'6ˆEÐ#Ñ$Ø!*ˆE�+ÑÜ1°&Ó9ˆE�%‰LÙŒIÜ$ UÔ+Ù˜˜~Ñ.Ó/÷c1	0ð 1	0÷;0ñ ;0÷	9ñ 	9ú÷<7ñ 7ú÷6Tð Tú÷I1	0ð 1	0úð 1	0÷;0÷ ;0ñ ;0úsˆ   ¡LÁ9A6MÃ/AL<Å	MÅ1L<Æ	
L#Æ$L<Æ7	MÇ
A8L<É	MÉAL<Ê&L0Ê:A	L<Ì	MÌL Ì#L-Ì(L<Ì0L9Ì5L<Ì<M	ÍMÍMz<Optional[Tuple[float, str, Optional[float], Dict[str, Any]]]Ú_nous_auth_status_cachez)Optional[Tuple[str, int, Dict[str, Any]]]r  c                 óš   — t        «       } 	 t        | «      | j                  «       j                  fS # t        $ r t        | «      d fcY S w xY wrl  )r  r.  r  Úst_mtimerÑ   )rx  s    rÔ   Ú_auth_file_cache_keyr  ê  sK   € ÜÓ!€Ið.Ü˜YÓ'¨¯©Ó)9×)BÑ)BÐBÐBøÜò .Ü˜YÓ'¨Ð-Ò-ð.ús   Œ$1 ±A
Á	A
c                 ó   — da y)z¹Clear the get_nous_auth_status() memo (for code paths that mutate Nous auth state without
    touching auth.json, e.g. tests; login/logout invalidate via the mtime check automatically).N)r  rê   rô   rÔ   Ú!invalidate_nous_auth_status_cacher  ò  s
   € ð #Ñrô   c                 óØ   — t        j                  «       } t        «       \  }}t        }|�'|dd ||fk(  r| |d   z
  t        k  rt        |d   «      S t        «       }| ||t        |«      fa|S )a  Status snapshot for Nous auth, memoised ~15s keyed on the auth.json mtime.

    Prefers the auth-store provider state (the live source of truth for refresh) and validates it by
    resolving runtime credentials so revoked refresh sessions do not show up as a healthy login.r8  é   r   )rV  rW  r  r  Ú_NOUS_AUTH_STATUS_CACHE_TTLró   r@   )r‡  Úauth_file_keyÚmtimer   Ústatuss        rÔ   Úget_nous_auth_statusr  ù  sy   € ô �.‰.Ó
€CÜ/Ó1Ñ€M�5Ü$€FØÐ˜v a¨˜{¨}¸eÐ.DÒDØ�v˜a‘y‘Ô$?Ò?Ü�F˜1‘I‹ÐÜ&Ó(€FØ" M°5¼$¸v»,ÐGÐØ€Mrô   )Úfrozenc                  ón   — e Zd ZU dZded<   ded<   ded<    e«       Zded<   dZd	ed
<   dd„Zdd„Z	dd„Z
y)ÚOAuthProviderFlowzýPer-provider OAuth plumbing, keyed by provider id in ``OAUTH_PROVIDER_FLOWS``.

    Callables are named (strings) and looked up in this module at call time so
    ``monkeypatch.setattr("hermes_cli.auth.resolve_codex_runtime_credentials", ...)`` applies.rØ   rÃ  Ú
resolve_fnÚ	status_fnrî  Úterminal_refresh_codesFrª  Úlogout_from_configc                ó<   —  t        «       | j                     di |¤ŽS )Nrê   )Úglobalsr#  )ÚselfÚkwargss     rÔ   r  zOAuthProviderFlow.resolve  s   € Ø)Œw‹y˜Ÿ™Ñ)Ñ3¨FÑ3Ð3rô   c                ó:   —  t        «       | j                     «       S rl  )r(  r$  )r)  s    rÔ   r  zOAuthProviderFlow.status  s   € Ø(Œw‹y˜Ÿ™Ñ(Ó*Ð*rô   c                óº   — t        |t        «      xrJ |j                  | j                  k(  xr/ |j                  | j
                  v xr t        |j                  «      S rl  )rm  rÄ   rË  rÃ  rï  r%  rª  rî  )r)  rå  s     rÔ   Úis_terminal_refresh_errorz+OAuthProviderFlow.is_terminal_refresh_error  sU   € ä�sœIÓ&ò W¨3¯<©<¸4×;KÑ;KÑ+Kò WØ—‘˜D×7Ñ7Ð7òWÜ<@À×AUÑAUÓ<Vð	Xrô   N)r*  r   r  rè   ©r  rè   )rå  rÑ   r  rª  )rî   rï   rð   rñ   rò   Ú	frozensetr%  r&  r  r  r-  rê   rô   rÔ   r"  r"  
  sD   … ñbð ÓØƒOØƒNÙ-6«[Ð˜NÓ8ð  %Ð˜Ó$ó4ó+ôXrô   r"  >   Úinvalid_grantÚinvalid_tokenÚrefresh_token_reused>   rü  r  r  r^   r  )r%  r&  r‹   Úget_codex_auth_statusÚcodex_refresh_failedÚ codex_auth_missing_refresh_tokenrz   Úget_xai_oauth_auth_statusÚxai_refresh_failedÚxai_auth_missing_refresh_tokenr—   r–   rl   Úget_minimax_oauth_auth_status)r÷   rù   rý   rþ   r)  zDict[str, OAuthProviderFlow]ÚOAUTH_PROVIDER_FLOWSc                ó2   — t         |   j                  | «      S )zDTrue when retrying the same *provider* refresh token cannot succeed.)r:  r-  )rå  rË  s     rÔ   Ú_is_terminal_refresh_errorr<  >  s   € ä Ñ)×CÑCÀCÓHÐHrô   )rË  c                 óì   — t        «       } | sy dt        t        «       «      | j                  d«      dd| j                  d«      xs d› �dt        | j                  d«      xs d| j                  d	«      d
œ	S )NTÚlast_refreshr‚  zpool:ÚlabelÚunknownrT  zCCodex provider quota exhausted; retry after the usage limit resets.Úreset_at)	r¥  rŠ  r>  Ú	auth_moderÄ  Úrate_limitedÚ
error_coderñ  rA  )r~   rØ   r  r¾  rÃ   )Ú
rate_limits    rÔ   Ú_codex_pool_rate_limited_statusrF  I  su   € Ü.Ó0€JÙØà¬¬_Ó->Ó)?Ø"Ÿ™ ~Ó6ÀYØ˜*Ÿ.™.¨Ó1Ò>°YÐ?Ð@ÐRVÜ-Ø—.‘. Ó+ò [ØZØ—N‘N :Ó.ñ0ð 0rô   c                 ó4   — t        dt        dd„ t        ¬«      S )z®Status snapshot for Codex auth (pool first, then legacy provider state).

    Read-only by contract: status/doctor must never adopt, refresh or persist a credential (#68004).rù   r‚  c                 ó   — t        d¬«      S )NT)Ú	read_only)r‹   rê   rô   rÔ   r•  z'get_codex_auth_status.<locals>.<lambda>]  s   € Ô9ÀDÔI€ rô   )Úis_expiringrB  r  Úon_pool_miss)rM   r{   rF  rê   rô   rÔ   r3  r3  W  s   € ô $ØÔ$CÈyÙIÜ4ô6ð 6rô   c                 ó*   — t        dt        dd„ ¬«      S )Nrý   rø   c                 ó   — t        d¬«      S )NF)Úrefresh_if_expiring)rz   rê   rô   rÔ   r•  z+get_xai_oauth_auth_status.<locals>.<lambda>f  s   € Ô=ÐRWÔX€ rô   )rJ  rB  r  )rM   rr   rê   rô   rÔ   r6  r6  a  s   € ô $ØÔ!>ÐJ]ÙXôZð Zrô   c                ó¤  — | j                   dk(  r†ddlm} t        «       j	                  d«      }t        |t        «      rW |t        |j	                  d«      xs d«      «      dk(  r0t        |j	                  d«      xs d«      j                  «       }|r|S | j                  r.t        j                  | j                  d«      j                  «       S dS )Nr"  r   )Únormalize_providerrÊ  rË  rÈ   rÒ   )rà   r6  rP  ru  r¾  rm  ró   rØ   rÙ   rí   r	  r”  )rá  rP  rÊ  Úconfigured_urls       rÔ   Ú_provider_env_base_urlrR  i  s¨   € Ø‡z�z�XÒÝ;äÓ!×%Ñ% gÓ.ˆÜ�eœTÔ"Ñ'9¼#¸e¿i¹iÈ
Ó>SÒ>YÐWYÓ:ZÓ'[Ð_gÒ'gÜ  §¡¨:Ó!6Ò!<¸"Ó=×CÑCÓEˆNÙØ%Ð%Ø>E×>VÒ>VŒ2�9‰9�W×-Ñ-¨rÓ2×8Ñ8Ó:Ð^Ð\^Ð^rô   c                óf  — t        | «      }|r|j                  dk7  rddiS t        | |«      \  }}t        |«      }| dv rt	        ||j
                  |«      }n|xs |j
                  }d}| dk(  rt        |«      }| xr t        |«      }t        |«      xs |}|| |j                  |xs |rdnd||dœS )	z<Status snapshot for API-key providers (z.ai, Kimi, MiniMax).r0  Ú
configuredF>   r  r  r"  úlocal-offlinerÈ   )rT  rË  rá   Ú
key_sourcerÒ   r¥  )
r¬  râ   rì  rR  r    rä   rÝ   rÕ   rª  rá   )rÃ  rá  r0  rV  Úenv_urlrÒ   Úactual_local_noauthrT  s           rÔ   Úget_api_key_provider_statusrY  u  sÑ   € ä˜{Ó+€GÙ�g×'Ñ'¨9Ò4Ø˜eÐ$Ð$Ü:¸;ÈÓPÑ€GˆZÜ$ WÓ-€GØÐ7Ñ7Ü)¨'°7×3MÑ3MÈwÓW‰àÒ8˜g×8Ñ8ˆØÐØ�hÒÜ,¨XÓ6ˆØ")˜kÒPÔ.FÀxÓ.PÐÜ�g“Ò5Ð"5€Jà ¨kÀ7Ç<Á<Ø ÒTÑ8K¡_ÐQSØ¨:ñ7ð 7rô   c                ó6   — | dk(  r
t        «       S |rdd|› �fS dS )a[  Best-effort POSITIVE evidence ``(verified, source)`` that an external-process CLI is authed.

    False means "not verifiable from here", NOT "signed out". Subprocess-free (spawning the CLI from
    status endpoints/pickers re-creates the cold-start stall copilot_auth.py avoids). Generic evidence
    for any external-process profile is its binary resolving: the subprocess owns real auth and Hermes
    has nothing else to inspect, so out-of-tree ACP rows pass credential-gated surfaces (Desktop
    ``explicit_only`` picker) like the bundled one, whose CLI additionally exposes readable token stores.r  Tz	command: ©FN)Ú_copilot_acp_auth_evidence)rÃ  Úresolved_commands     rÔ   Ú_external_process_auth_evidencer^  ‹  s0   € ð �mÒ#Ü)Ó+Ð+Ù5EˆD�IÐ.Ð/Ð0Ð1ÐXÈ=ÐXrô   c                 óF  — 	 ddl m} m} | D ]=  }t        j                  |d«      j                  «       }|sŒ* ||«      d   sŒ6dd|› �fc S  	 	 t        j                  j                  d«      }t        j                  j                  |«      r³t        |d	d
d¬«      5 }dj                  d„ |j                  «       j                  «       D «       «      }ddd«       j                  «       rt!        j"                  |«      ni j%                  d«      }t'        |t(        «      r!t+        d„ |j-                  «       D «       «      rydD ]i  }		 t        j                  j                  |	«      }
t        j                  j                  |
«      r(t        j                  j/                  |
«      dkD  rd|	fc S Œk y# t        $ r!}t        j                  d|«       Y d}~�Œ†d}~ww xY w# 1 sw Y   �ŒxY w# t        $ r }t        j                  d|«       Y d}~ŒÍd}~ww xY w# t0        $ r Y ŒÞw xY w)zaCopilot CLI token stores readable without spawning it (env tokens, plaintext config, hosts.json).r   )ÚCOPILOT_ENV_VARSÚvalidate_copilot_tokenrÈ   Tzenv: z/copilot-acp env token evidence check failed: %sNú~/.copilot/config.jsonro  rL  Úignore)rN  ÚerrorsrR  c              3  ó`   K  — | ]&  }|j                  «       j                  d «      rŒ#|–— Œ( y­w)z//N)Úlstripr¤  )rn  Úlines     rÔ   rp  z-_copilot_acp_auth_evidence.<locals>.<genexpr>©  s+   è ø€ ò  cØ!À4Ç;Á;Ã=×C[ÑC[Ð\`ÕCa”Dñ cùs   ‚$.§.ÚcopilotTokensc              3  ó`   K  — | ]&  }t        |t        «      xr |j                  «       –— Œ( y ­wrl  )rm  rØ   rÙ   r~  s     rÔ   rp  z-_copilot_acp_auth_evidence.<locals>.<genexpr>¬  s,   è ø€ ò 0KØ56”
˜1œcÓ"Ò0 q§w¡w£yÓ0ñ0Kùs   ‚,.)Trb  z0copilot-acp CLI config evidence check failed: %s)z#~/.config/github-copilot/hosts.jsonz"~/.config/github-copilot/apps.jsonr  r[  )rÙ  r`  ra  r	  r”  rÙ   rÑ   rÀ  rw  rÚ   Ú
expanduserÚisfilerU  rÂ  ÚreadrV  rr  rs  r¾  rm  ró   r¿  r  Úgetsizer+  )r`  ra  ræ  r¼  rå  Ú
cli_configÚfhry  ÚtokensÚ	cred_pathÚexpandeds              rÔ   r\  r\  ˜  sá  € ðMßTØ'ò 	/ˆGÜ—)‘)˜G RÓ(×.Ñ.Ó0ˆCÚÑ-¨cÓ2°1Ó5Ø˜u W IÐ.Ð.Ò.ñ	/ðNÜ—W‘W×'Ñ'Ð(@ÓAˆ
Ü�7‰7�>‰>˜*Ô%Ü�j #°ÀÔIð cÈRØ—i‘iñ  cØ%'§W¡W£Y×%9Ñ%9Ó%;ô có c�÷cð *-¯©¬”d—j‘j ”o¸"×AÑAÀ/ÓRˆFÜ˜&¤$Ô'¬Cñ 0KØ:@¿-¹-»/ô0Kô -Kà5ð cò ˆ	ð	Ü—w‘w×)Ñ)¨)Ó4ˆHÜ�w‰w�~‰~˜hÔ'¬B¯G©G¯O©O¸HÓ,EÈÒ,IØ˜Y�Ò&øð	ð øô1 ò MÜ�‰ÐFÈ×LÒLûðMú÷cñ cûô ò NÜ�‰ÐGÈ×MÑMûðNûô ò 	Ùð	úsm   ‚3F. ¶F. ÁF. ÁF. ÁAG( Â5GÃA.G( ÅA#HÆ.	GÆ7GÇGÇG%Ç G( Ç(	HÇ1HÈHÈ	H ÈH c                óN  — t        | «      xs | j                  }	 ddlm}  || j                  «      }t        t        |dd«      xs d«      }t        t        |dd«      xs d«      }t        d„ d	„ |D «       D «       d«      xs t        t        |d
d«      xs d«      }|r$t        j                  |d«      j                  «       nd}|rt        j                  |«      nt        t        |dd«      xs g «      }||||rt!        j"                  |«      |fS d|fS # t
        $ r d}Y Œðw xY w)a  ``(command, args, base_url, resolved_command, command_env_vars)`` for an ACP provider.

    Launch details come from the provider's own profile (copilot-acp: HERMES_COPILOT_ACP_COMMAND /
    COPILOT_CLI_PATH / HERMES_COPILOT_ACP_ARGS), so out-of-tree providers describe their binary.r   )Úget_provider_profileNÚprocess_command_env_varsrê   Úprocess_args_env_varrÈ   c              3  ó&   K  — | ]	  }|sŒ|–— Œ y ­wrl  rê   r~  s     rÔ   rp  z)_external_process_spec.<locals>.<genexpr>Ê  s   è ø€ Ò^˜1Ò\]”QÑ^ùr€  c              3  ód   K  — | ](  }t        j                  |d «      j                  «       –— Œ* y­wr‚  )r	  r”  rÙ   )rn  rƒ  s     rÔ   rp  z)_external_process_spec.<locals>.<genexpr>Ê  s$   è ø€ Ò XÀ¤§¡¨3°Ó!3×!9Ñ!9×!;Ñ Xùs   ‚.0Úprocess_commandÚprocess_args)rR  rä   rj  rt  rà   rÑ   rë   rà  rØ   r†  r	  r”  rÙ   Úshlexr  r»  ru  Úwhich)	rá  rÒ   Ú_get_provider_profileÚprofileÚcommand_env_varsÚargs_env_varÚcommandÚraw_argsÚargss	            rÔ   Ú_external_process_specr„  ¼  s!  € ô & gÓ.ÒL°'×2LÑ2L€HðÝKÙ'¨¯
©
Ó3ˆô œW WÐ.HÈ"ÓMÒSÐQSÓTÐÜ”w˜wÐ(>ÀÓCÒIÀrÓJ€LÜÑ^Ñ XÐGWÔ XÔ^Ð`bÓcò EÜ”g˜gÐ'8¸"Ó=ÒCÀÓDð á6BŒr�y‰y˜ rÓ*×0Ñ0Ô2È€HÙ$,Œ5�;‰;�xÔ ´$´w¸wÈÐXZÓ7[Ò7aÐ_aÓ2b€DØ�D˜(¹W¤F§L¡L°Ó$9ÐP`Ð`Ð`È$ÐP`Ð`Ð`øô ò ØŠðús   ›D ÄD$Ä#D$c                óì   — t        | «      }|r|j                  dk7  rddiS t        |«      \  }}}}}t        |xs |j	                  d«      «      }t        | |«      \  }}	|| |j                  |||||||	dœ
S )zùStatus snapshot for providers that run a local subprocess.

    ``configured``/``logged_in`` are structural (executable resolves or TCP endpoint set): the
    subprocess owns real auth. ``auth_verified``/``auth_source`` carry positive evidence only.r  rT  Fú
acp+tcp://)
rT  rË  rá   r�  rƒ  r]  rÒ   r¥  Úauth_verifiedÚauth_source)r¬  râ   r„  rª  r¤  r^  rá   )
rÃ  rá  r�  rƒ  rÒ   r]  r¢  Ú	availabler‡  rˆ  s
             rÔ   Ú$get_external_process_provider_statusrŠ  Ñ  s–   € ô
 ˜{Ó+€GÙ�g×'Ñ'Ð+=Ò=Ø˜eÐ$Ð$Ü3IÈ'Ó3RÑ0€GˆT�8Ð-¨qÜÐ%ÒJ¨×)<Ñ)<¸\Ó)JÓK€IÜ!@ÀÐN^Ó!_Ñ€M�;à¨[À'Ç,Á,Ð[bØÐ*:ÈØ°È{ñ\ð \rô   c                óN   — 	 ddl m}  |«       | dœS # t        $ r	 d| ddœcY S w xY w)uA   AWS SDK providers (Bedrock) â€” check via boto3 credential chain.r   r¹  ©r¥  rË  Fzboto3 not installed)r¥  rË  rñ  )r½  rº  r—  )r�  rº  s     rÔ   Ú_get_aws_sdk_auth_statusr�  â  s8   € ðXÝ=Ù0Ó2ÀÑGÐGøÜò XØ"°ÐAVÑWÒWðXús   ‚ ’$£$c                óJ  — | xs t        «       xs dj                  «       j                  «       }|sddiS t        j	                  |«      }|r t        «       |   «       S t        |«      }|r6|j                  t        v r$ t        «       t        |j                        |«      S ddiS )af  Generic auth status dispatcher: bespoke builders (``OAUTH_PROVIDER_FLOWS`` plus Spotify /
    Azure Foundry) first, then the registry ``auth_type`` so a whole provider class (e.g. every
    external-process ACP backend) gets a real status. Builders are looked up by NAME at call time so
    tests that patch ``hermes_cli.auth.get_*_auth_status`` still apply.rÈ   r¥  F)	r  rÙ   rÏ   Ú_BESPOKE_STATUS_FUNCTIONSr¾  r(  r¬  râ   Ú_STATUS_BY_AUTH_TYPE)rÃ  r�  Ústatus_fn_namerá  s       rÔ   r§  r§  ë  s¢   € ð
 Ò8Ô0Ó2Ò8°b×?Ñ?ÓA×GÑGÓI€FÙØ˜UÐ#Ð#Ü.×2Ñ2°6Ó:€NÙØ(Œw‹y˜Ñ(Ó*Ð*Ü˜vÓ&€GÙ�7×$Ñ$Ô(<Ñ<ØAŒw‹yÔ-¨g×.?Ñ.?Ñ@ÑAÀ&ÓIÐIØ˜ÐÐrô   r�   Ú_get_azure_foundry_auth_status)Úspotifyrg  r�  rŠ  rY  r�  rw  )r  r0  re  rø   rú   r�  c            	     óh  — ddi} 	 ddl m}m}  |«       }t	        |t
        «      r|j                  d«      nd}t	        |t
        «      si }t        |j                  d«      xs d«      j                  «       j                  «       xs d}|| d<   t        |j                  d	«      xs d
«      j                  «       | d	<   |dk(  r{	 ddl
m}m}m}  |«       }	t	        |j                  d«      t
        «      r|d   ni }
|j                  |
|¬«      }| j                  |	|j                   ddt#        |	«      |	rdnd¬«       | S 	  d«      xs d
}t)        |«      | d<   | S # t        $ r i }Y �ŒRw xY w# t        $ r}d| d<   d|› �| d<   Y d}~| S d}~ww xY w# t        $ r t%        j&                  dd
«      }Y Œgw xY w)u	  Structural auth status for Azure Foundry.

    ``entra_id``: ``azure-identity`` importable â€” never invokes the Entra credential chain (keeps
    CLI startup flat; ``hermes doctor`` runs the live probe). ``api_key`` (default): usable
    ``AZURE_FOUNDRY_API_KEY``.rË  rg  r   )rÉ  r|  rÊ  NrB  r0  rÒ   rÈ   Úentra_id)ÚEntraIdentityConfigÚSCOPE_AI_AZURE_DEFAULTÚhas_azure_identity_installedÚentra)Údefault_scopeÚnot_runFzyazure-identity is installed; live credential validation is skipped here. Run `hermes doctor` to verify token acquisition.zwazure-identity not installed. Install with: pip install azure-identity  (or rely on Hermes' lazy-install at first use).)Úazure_identity_installedræ   Úcredential_probeÚcredential_verifiedr¥  rU  r¥  zazure-identity check failed: rñ  rh  )r…  rÉ  r|  rÑ   rm  ró   r¾  rØ   rÙ   rÏ   Úagent.azure_identity_adapterr–  r—  r˜  rÕ  Úupdateræ   rª  r	  r”  r¶  )ÚinforÉ  r|  r  rÎ  rB  r–  r—  r˜  Ú	installedÚ	entra_cfgÚidentity_configrå  r0  s                 rÔ   r’  r’    sÓ  € ð '¨Ð8€DðßNÙ‹mˆô %/¨s´DÔ$9�—‘˜Ô ¸t€IÜ�i¤Ô&Øˆ	Ü�I—M‘M +Ó.Ò;°)Ó<×BÑBÓD×JÑJÓLÒYÐPY€IØ!€DˆÑÜ˜9Ÿ=™=¨Ó4Ò:¸Ó;×AÑAÓC€DˆÑà�JÒð	B÷[ñ [á4Ó6ˆIÜ.8¸¿¹ÀwÓ9OÔQUÔ.V˜	 'Ò*Ð\^ˆIØ1×;Ñ;¸IÐUkÐ;ÓlˆOØ�K‰KØ)2¸/×:OÑ:OÐbkØ$)´T¸)³_ñ ñXð2ð ô 	4ð ˆð9Ù-Ð.EÓFÒLÈ"ˆô *¨'Ó2€DˆÑØ€KøôI ò Ø‹ðûô4 ò 	BØ %ˆD�ÑØ;¸C¸5ÐAˆD��MØˆûð	Bûô ò 9Ü—)‘)Ð3°RÓ8Šð9ús<   †E ÃA8E+ Ä=F ÅE(Å'E(Å+	FÅ4FÆFÆF1Æ0F1c                ó,   — |r|j                  d«      S |S )Nr×   )rÐ   )r0  ÚdefaultrW  s      rÔ   Ú_default_api_key_base_urlr§  <  s   € Ù")ˆ7�>‰>˜#ÓÐ6¨wÐ6rô   c                óæ   — t        | ||«      }	 ddlm}m}  |«       \  }}|r! ||«      d   xs dj	                  «       }|r|}|S # t
        $ r!}	t        j                  d|	«       Y d}	~	|S d}	~	ww xY w)z¶Copilot's API base comes from the token-exchange response (endpoints.api, proxy-ep fallback),
    authoritative for Enterprise / proxied accounts; falls back to the registry default.r   rÑ  r8  rÈ   z4Copilot base URL resolution fell back to default: %sN)r§  rÙ  rÒ  rÓ  rÙ   rÑ   rÀ  rw  )
r0  r¦  rW  rÒ   rÒ  rÓ  Ú	raw_tokenr¢  Úresolvedrå  s
             rÔ   Ú_copilot_runtime_base_urlr«  @  s�   € ô )¨°'¸7ÓC€HðRßXÙ,Ó.‰ˆ	�1ÙÙ-¨iÓ8¸Ñ;ÒA¸r×HÑHÓJˆHÙØ#�ð €Oøô ò RÜ�‰ÐKÈS×QÐQØ€OûðRús   �5A Á	A0ÁA+Á+A0c                 ó$   — t        t        | Ž «      S rl  )r   r§  ©Úas    rÔ   r•  r•  W  s   € Ô?Ô@YÐ[\Ð@]Ó^€ rô   c                 ó$   — t        t        | Ž «      S rl  )rÝ   r§  r­  s    rÔ   r•  r•  X  s   € Ô2Ô3LÈaÐ3PÓQ€ rô   )r  r  r  r  rÿ   r"  z)Dict[str, Callable[[str, str, str], str]]Ú_API_KEY_BASE_URL_RESOLVERSc                ó²  — t        | «      }|r|j                  dk7  rt        d| › d�| d¬«      ‚t        | |«      \  }}|s| dk(  rt        }|xs d}t        |«      }t        j                  | t        «      } |||j                  |«      }t        |«      s|j                  }|s| dk(  rt        |«      rt        }|xs d	}| ||j                  d
«      |xs ddœS )z5Resolve API key and base URL for an API-key provider.r0  ú
Provider 'z' is not an API-key provider.r¸  ©rË  rï  rÿ   r¦  r"  rU  r×   )rË  r0  rÒ   rÄ  )r¬  râ   rÄ   rì  rÁ   rR  r°  r¾  r§  rä   r  rÕ   rÂ   rÐ   )rÃ  rá  r0  rV  rW  Úresolve_urlrÒ   s          rÔ   Ú$resolve_api_key_provider_credentialsrµ  [  sô   € ä˜{Ó+€GÙ�g×'Ñ'¨9Ò4ÜØ˜˜Ð%BÐCØ Ð'9ô;ð 	;ô ;¸;ÈÓPÑ€GˆZñ �{ jÒ0Ü-ˆØÒ, 9ˆ
ä$ WÓ-€GÜ-×1Ñ1°+Ô?XÓY€KÙ˜7 G×$>Ñ$>ÀÓH€Hô ˜Ô"Ø×-Ñ-ˆá�{ hÒ.Ô3KÈHÔ3UÜ1ˆØÒ2 ?ˆ
à¨GÀÇÁÐQTÓAUØÒ) 	ñ+ð +rô   c           	     ób  — t        | «      }|r|j                  dk7  rt        d| › d�| d¬«      ‚t        |«      \  }}}}}|sE|j	                  d«      s4|rddj                  |«      z   nd	}t        d
| › d|xs d› d|› d�| d¬«      ‚| |j                  xs | |j                  d«      |xs ||ddœS )z>Resolve runtime details for local subprocess-backed providers.r  r²  z&' is not an external-process provider.r¸  r³  r†  z or set r×   rÈ   zCould not find the 'z' CLI command 'z(none configured)z'. Install itrÉ   Úmissing_external_process_cliÚprocess)rË  r0  rÒ   r�  rƒ  rÄ  )r¬  râ   rÄ   r„  r¤  rÂ  rà   rÐ   )rÃ  rá  r�  rƒ  rÒ   r]  r  Ú_hints           rÔ   Ú-resolve_external_process_provider_credentialsrº  z  sï   € ä˜{Ó+€GÙ�g×'Ñ'Ð+=Ò=ÜØ˜˜Ð%KÐLØ Ð'9ô;ð 	;ô CYÐY`ÓBaÑ?€GˆT�8Ð-Ð/?Ù H×$7Ñ$7¸Ô$EÙ;K�
˜SŸX™XÐ&6Ó7Ò7ÐQSˆÜØ" ; -ð 0ØÒ.Ð.Ð/¨}¸U¸GÀ1ðFà Ø/ô	1ð 	1ð  ¨G¯J©JÒ,E¸+Ø—O‘O CÓ(Ð5EÒ5PÈÐZ^Øñð rô   )Úclear_defaultc               ó¬  — t        «       5  t        «       }| |d<   t        |«       ddd«       t        «       }|j                  j                  dd¬«       t        |«       t        «       }|j                  d«      }t        |t        «      rt        |«      }nt        |«      rd|j                  «       ini }| |d<   |r%|j                  «       r|j                  d«      |d	<   n|j                  d	d«       d
dlm}	  |	|«       |r|j                  dd«      }
|
rd|
v r||d<   n|r|j                  dd«       ||d<   t#        ||«       |S # 1 sw Y   �Œ%xY w)a
  Update config.yaml and auth.json to reflect the active provider.

    *default_model*, when given, is written as ``model.default`` in the same step so the gateway
    (which re-reads config per message) can't pick up the new provider before model selection
    finishes and send an OpenRouter-style ``vendor/model`` name to a direct API. *clear_default*
    removes ``model.default`` in that same write, for a caller that has no model to offer and must
    not leave the previous provider's model paired with the new host.rq  NTrI  rÊ  r¦  rË  r×   rÒ   r   )Ú clear_model_endpoint_credentialsrÈ   )rg  r  r‹  rt  rO  rP  rv  ru  r¾  rm  ró   r  rÙ   rÐ   r   r…  r½  rr  )rÃ  rä   Údefault_modelr»  rŠ  Úconfig_pathÚconfigÚcurrent_modelrÎ  r½  Úcur_defaults              rÔ   Ú_update_config_for_providerrÃ  ”  sJ  € ô 
Ó	ñ %Ü%Ó'ˆ
Ø(3ˆ
Ð$Ñ%Ü˜Ô$÷%ô
 "Ó#€KØ×Ñ×Ñ T°DÐÔ9Ü(¨Ô5ÜÓ€FØ—J‘J˜wÓ'€MÜ�-¤Ô&Ü˜Ó'‰	ä:GÈÔ:V�Y × 3Ñ 3Ó 5Ñ6Ð\^ˆ	Ø'€IˆjÑÙÐ0×6Ñ6Ô8Ø 2× 9Ñ 9¸#Ó >ˆ	�*Òà�‰�j $Ô'õ CÙ$ YÔ/ñ Ø—m‘m I¨rÓ2ˆÙ˜c [Ñ0Ø#0ˆI�iÒ Ù	Ø�‰�i Ô&Ø€Fˆ7�OÜ˜ VÔ,ØÐ÷G%ñ %ús   ‹E	Å	Ec                 ó  — 	 t        «       } | r| j                  d«      nd}t        |t        «      r|j                  d«      nd}t        |t
        «      r"|j                  «       j                  «       xs dS dS # t        $ r Y yw xY w)z?Return model.provider from config.yaml, normalized, if present.NrÊ  rË  )ru  rÑ   r¾  rm  ró   rØ   rÙ   rÏ   )rÀ  rÊ  rË  s      rÔ   Ú_get_config_providerrÅ  Ä  sz   € ðÜ Ó"ˆñ $*ˆF�J‰J�wÔ¨t€EÜ(2°5¼$Ô(?ˆu�y‰y˜Ô$ÀT€HÜ1;¸HÄcÔ1JˆH�N‰NÓ×"Ñ"Ó$Ò,¨ÐTÐPTÐTøô	 ò Ùðús   ‚
A8 Á8	BÂBc                ót   — | xs dj                  «       j                  «       }|t        v xr t        «       |k(  S )zWTrue when logout should reset model.provider (a registry provider config.yaml selects).rÈ   )rÙ   rÏ   rq  rÅ  r­  s     rÔ   Ú'_should_reset_config_provider_on_logoutrÇ  Ï  s8   € àÒ# ×*Ñ*Ó,×2Ñ2Ó4€JØÔ*Ð*ÒSÔ/CÓ/EÈÑ/SÐSrô   c                 ól   — t        «       } t        j                  | xs d«      }|r|j                  r| S dS )uç   Fallback logout target when auth.json has no active provider but config.yaml still selects an
    OAuth provider (e.g. openai-codex) â€” otherwise logout said "No provider is currently logged in"
    and never reset model.provider.rÈ   N)rÅ  r:  r¾  r&  )rË  Úflows     rÔ   Ú$_logout_default_provider_from_configrÊ  Õ  s5   € ô $Ó%€HÜ×#Ñ# H¢N°Ó3€DÙ × 7Ò 7ˆ8ÐA¸TÐArô   c                 óî   — t        «       } | j                  «       s| S t        | «       t        «       }|s| S |j	                  d«      }t        |t        «      rd|d<   d|v r	t        |d<   t        | |«       | S )z5Reset config.yaml provider back to auto after logout.rÊ  r´  rË  rÒ   )	rt  r  rv  ru  r¾  rm  ró   r   rr  )r¿  rÀ  rÊ  s      rÔ   Ú_reset_config_providerrÌ  Þ  sy   € ä!Ó#€KØ×ÑÔØÐÜ(¨Ô5ÜÓ€FÙØÐØ�J‰J�wÓ€EÜ�%œÔØ"ˆˆjÑØ˜ÑÜ 3ˆE�*ÑÜ˜ VÔ,ØÐrô   c                ó.   — t        d«       t        d«      ‚)z9Deprecated: use 'hermes model' or 'hermes setup' instead.zœThe 'hermes login' command has been removed.
Use 'hermes auth' to manage credentials,
'hermes model' to select a provider, or 'hermes setup' for full setup.r   )ÚprintÚ
SystemExit)rƒ  s    rÔ   Úlogin_commandrÐ  ð  s   € ä	ð Sô Tä
�Q‹-Ðrô   c                 óH  — t        d«      } | r| j                  d«      sdddœS 	 t        j                  | j                  dd«      «      j	                  «       t        j
                  «       kD  }|d| j                  dd	«      | j                  d«      d
œS # t        $ r d}Y Œ3w xY w)z3Return auth status dict for MiniMax OAuth provider.r)  r×  FrŒ  rÞ  rÈ   Tr,  r+  )r¥  rË  r,  rÞ  )r  r¾  r	   rÊ  rË  rV  rÑ   )r‘  Útoken_valids     rÔ   r9  r9  ÷  sŸ   € ä# OÓ4€EÙ˜Ÿ	™	 .Ô1Ø"°Ñ@Ð@ðÜ×,Ñ,¨U¯Y©Y°|ÀRÓ-HÓI×SÑSÓUÔX\×XaÑXaÓXcÑcˆð !¨oØ—)‘)˜H hÓ/¸u¿y¹yÈÓ?VñXð Xøô ò ØŠðús   ¥AB ÂB!Â B!c                óD  — t        | dd«      }|r$t        |«      st        d|› �«       t        d«      ‚|xs t	        «       xs
 t        «       }|st        d«       y|dk(  r%ddlm}m}  |t        d«      «      rt        |«       yt        |«      }t        |«      }t        |«      s|st        d	|› d
�«       y|dk(  rddlm}  |d«       |r
t        «        t        d|› d
�«       |st        d«       yt!        j"                  d«      rt        d«       yt        d«       y)z Clear auth state for a provider.rË  NzUnknown provider: r8  z#No provider is currently logged in.r÷   r   )ÚFREE_TIER_NOT_SIGNED_INr  zNo auth state found for rÉ   )Ú_clear_shared_nous_stateÚlogoutzLogged out of z+Model provider configuration was unchanged.rœ  z)Hermes will use OpenRouter for inference.z9Run `hermes model` or configure an API key to use Hermes.)rà  r¯  rÎ  rÏ  r  rÊ  r¦  rÔ  r  r  rÇ  r±  rH  Úhermes_cli.auth_nousrÕ  rÌ  r	  r”  )rƒ  rÃ  r�  rÔ  r  Úshould_reset_configrW  rÕ  s           rÔ   Úlogout_commandrÙ  	  s  € ä˜$ 
¨DÓ1€KÙÔ1°+Ô>ÜÐ" ; -Ð0Ô1Ü˜‹mÐØÒ[Ô/Ó1Ò[Ô5YÓ5[€FÙÜÐ3Ô4ØØ�ÒßPÙÔ1°&Ó9Ô:äÐ)Ô*ØÜAÀ&ÓIÐÜ2°6Ó:€MÜ Ô'Ñ+>ÜÐ(¨¨°qÐ9Ô:ØØ�ÒåAÙ  Ô*ÙÜÔ Ü	ˆN˜=˜/¨Ð
+Ô,ÙÜÐ;Õ<Ü	�‰Ð'Ô	(ÜÐ9Õ:äÐIÕJrô   )ÚBaseHTTPRequestHandler)Ú
HTTPServer)ÚTYPE_CHECKING)Úparse_qs)Ú	urlencodeÚCODEX_OAUTH_USER_AGENT)úhermes_cli.auth_constantsrß  Ú&CODEX_QUOTA_PROBE_MIN_INTERVAL_SECONDS)zhermes_cli.auth_codexrá  ÚDEFAULT_SPOTIFY_REDIRECT_URI)rà  râ  Ú%DEVICE_AUTH_POLL_INTERVAL_CAP_SECONDS)rà  rã  ÚMINIMAX_OAUTH_GRANT_TYPE)rà  rä  ÚNOUS_INFERENCE_INVOKE_SCOPE)rà  rå  ÚNOUS_SHARED_STORE_FILENAME)úhermes_cli.auth_nousræ  ÚOAUTH_OVER_SSH_DOCS_URL)rà  rè  ÚQWEN_OAUTH_CLIENT_ID)rà  ré  ÚQWEN_OAUTH_TOKEN_URL)rà  rê  Ú SINGLE_USE_OAUTH_SINGLETON_FILES)zhermes_cli.auth_oauth_grantsrë  Ú)SPOTIFY_ACCESS_TOKEN_REFRESH_SKEW_SECONDS)rà  rì  ÚSPOTIFY_DASHBOARD_URL)rà  rí  ÚXAI_OAUTH_DEVICE_CODE_URL)rà  rî  ÚXAI_OAUTH_DISCOVERY_URL)rà  rï  ÚXAI_OAUTH_ISSUER)rà  rð  Úrefresh_nous_oauth_pure)rç  rñ  c                óÌ   — t         j                  | «      }|€t        dt        ›d| ›�«      ‚dd l}ddlm}  |t        | g|¢­Ž  t        |j                  |d   «      |d   «      S )Nzmodule z has no attribute r   )Ú	warn_oncer8  )	Ú_PLUGIN_COMPAT_LAZYr¾  ÚAttributeErrorrî   Ú	importlibÚhermes_cli.plugin_compatró  rà  Úimport_module)rá   r�  rö  ró  s       rÔ   Ú__getattr__rù  N	  se   € Ü ×$Ñ$ TÓ*€FØ€~Ü˜w¤x lÐ2DÀTÀHÐMÓNÐNÛÝ2ÙŒh˜Ð&˜vÓ&Ü�9×*Ñ*¨6°!©9Ó5°v¸a±yÓAÐArô   )rÒ   rØ   r  rª  )rÒ   rØ   r  rØ   )rÈ   r0  )rà   rØ   rá   rØ   rä   rØ   rì   rë   rí   rØ   râ   rØ   r  rß   )r  rØ   )r«  rØ   r  rª  )r«  r   r²  ré  r  rª  )rÃ  rØ   r«  r   rÄ  rØ   r  úOptional[str])rÃ  rØ   r  rØ   )rÃ  rØ   rá  rß   r  útuple[str, str])rñ  rÑ   r  rª  )rñ  rÑ   r  rû  )rñ  rÑ   r  rØ   )r«  r   r  rª  )r  r   )r  úOptional[Path]r.  )r'  r   r(  r   r  rª  )rÚ   r   r  rØ   )r5  r   r  úthreading.local)rD  r   rE  rª  r  ÚNone)r]  r   r^  rý  r_  Úfloatr`  rØ   )r_  rÿ  r5  rü  rl  )rx  rü  r  rè   )
r�  r   r‚  r   r}  rª  rƒ  r   r  rþ  )rŠ  rè   r5  rü  r  r   )rŠ  rè   rë  rØ   r  rè   )r"  rè   rÃ  rØ   r  úOptional[Dict[str, Any]])rŠ  rè   rÃ  rØ   r  z/tuple[Optional[Dict[str, Any]], Optional[Path]])rŠ  rè   rÃ  rØ   r  r   )rÃ  rØ   r_  rÿ  )
rŠ  rè   rÃ  rØ   r‘  rè   r�  rª  r  rþ  )rŠ  rè   rÃ  rØ   r‘  rè   r  rþ  )rÃ  rØ   r‘  rè   r  r   )
rÃ  rØ   r‘  rè   r5  r   r�  rª  r  r   )
rŠ  rè   rÃ  rØ   r‘  rè   rš  rü  r  rþ  )rÃ  rØ   r  rþ  )rÃ  rØ   r  rª  )rÃ  rú  r  rè   )ré  rè   rÖ  r   rÃ  rØ   r  rè   )rÞ  zIterable[Any]r  zDict[str, Dict[str, Any]])
rÃ  rØ   rÞ  zList[Dict[str, Any]]rå  úOptional[Iterable[str]]ræ  r  r  r   )rô  rè   rÃ  rØ   r  zOptional[List[str]])rÃ  rØ   rÄ  rØ   r  rþ  )rÃ  rØ   rÄ  rØ   r  rª  )rÃ  rØ   r  r   )r  rª  )r  rú  )r®  rØ   r  rª  )r  r   r®  rØ   r  rª  )rá   rØ   r  rª  )ré  r   r  rª  )rÃ  rú  r  rª  )r  rþ  )rW  rØ   r  rØ   )r  r‡  )r  úCallable[[str], str])r›  r  r  rª  )r   rª  r  rú  )r  zTuple[Any, Optional[str]])r›  r  r²  rú  r  rú  )
r¾  rú  rµ  rú  r¶  rú  r   rª  r  rØ   )r«  r   r  zOptional[float])rÏ  r   rÐ  ré  r  rª  )rÖ  r   r  rè   )
rË  rØ   rñ  ú'AuthError'rÚ  rØ   rØ  rú  r  rè   )r‘  rè   rË  rØ   rå  r  r  rþ  )rß  r   r  ré  )r«  r   r  rú  )r‘  rè   r  rØ   )
r_  rÿ  rÔ  zOptional[bool]rÕ  rú  rö  ré  r  rØ   )r  zTuple[str, Optional[float]])rå  rÑ   rË  rØ   r  rª  )r  r   )rá  rß   r  rØ   )rÃ  rØ   r  rè   )rÃ  rØ   r]  rú  r  útuple[bool, Optional[str]])r  r  )rá  rß   r  z:tuple[str, List[str], str, Optional[str], tuple[str, ...]])r�  rØ   r  rè   )r0  rØ   r¦  rØ   rW  rØ   r  rØ   )
rÃ  rØ   rä   rØ   r¾  rú  r»  rª  r  r   (™  rñ   Ú
__future__r   rr  Úloggingr	  ru  r{  r2  rV  Ú
webbrowserÚ
contextlibr   r   Údataclassesr   r   Ú	functoolsr   r	   r
   Úpathlibr   Útypingr   r   r   r   r   r   r   r   Úurllib.parser   rþ  r   r   r   Úagent.credential_persistencer   Úutilsr   r   r   r   Úhermes_cli.auth_zai_kimir   r   r   r    r!   r"   Úhermes_cli.auth_model_pickerr#   r$   Úhermes_cli.auth_device_flowr%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   Úhermes_cli.auth_oauth_grantsr3   r4   r5   r6   r7   r8   r×  r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   rJ   rK   rL   rM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r\   r]   r^   r_   Úhermes_cli.auth_minimaxr`   ra   rb   rc   rd   re   rf   rg   rh   ri   rj   rk   rl   Úhermes_cli.auth_xairm   rn   ro   rp   rq   rr   rs   rt   ru   rv   rw   rx   ry   rz   Úhermes_cli.auth_codexr{   r|   r}   r~   r   r€   r�   r‚   rƒ   r„   r…   r†   r‡   rˆ   r‰   rŠ   r‹   Úhermes_cli.auth_spotifyrŒ   r�   rŽ   r�   Úhermes_cli.auth_openrouterr�   Úhermes_cli.auth_qwenr‘   r’   r“   r”   r•   r–   r—   Úhermes_cli.auth_constantsr˜   r™   rš   r›   rœ   r�   rž   rŸ   r    r¡   r¢   r£   r¤   r¥   r¦   r§   r¨   r©   rª   r«   r¬   r­   r®   r¯   r°   r±   r²   r³   r´   rµ   r¶   r·   r¸   r¹   rº   r»   r¼   r½   r¾   r¿   rÀ   rÁ   rÂ   rÃ   rÄ   rÅ   rÆ   Ú	getLoggerrî   rÀ  r9  rÑ   r@  rÕ   rÝ   rß   rö   rj  rò   rà   rq  r/  ÚBUILTIN_PROVIDER_IDSr…  rr  rs  rt  ru  rv  Ú hermes_cli.auth_plugin_providersrw  rx  r¬  ry  rˆ  r´  r¦  r°  r¶  r¸  rÆ  rÏ  rì  rò  rô  r   rÿ  r  r  r  r  r#  r$  ÚLockr0  r  r,  r.  r6  rF  rc  rg  rk  r  r„  r‹  r�  r’  r–  r˜  r›  rŸ  r¡  r£  r¥  r§  r©  r¯  r±  r¸  rÃ  rÔ  rá  rä  rò  rö  rû  rý  r  r  r  r  r  r  r"  r&  r2  r:  r=  r-  r7  r%  r@  rA  rE  rH  rJ  r[  ra  rˆ  r�  r˜  rž  r©  r¯  r±  r´  r·  rÆ  rÍ  rÒ  r×  rÜ  rå  rç  rê  rì  rï  rù  rð  r  rô  r  r  r  r  r  r  r  r"  Ú_OAUTH_GRANT_DEAD_CODESÚ_NOUS_AUTH_MISSING_CODESr:  r<  Ú_is_terminal_nous_refresh_errorÚ$_is_terminal_xai_oauth_refresh_errorÚ&_is_terminal_codex_oauth_refresh_errorrF  r3  r6  rR  rY  r^  r\  r„  rŠ  r�  r§  rº  r$  r�  r�  r’  r§  r«  r°  rµ  rº  rÃ  rÅ  rÇ  rÊ  rÌ  rÐ  r9  rÙ  Úhttp.serverrÚ  rÛ  rÜ  Úbase64ÚhashlibrÝ  ÚsslÚ
subprocessÚsysrÞ  rô  rù  )r»  r³  rÉ  s   000rÔ   ú<module>r*     sá  ðò	Xõ #ã Û Û 	Û Û Û Û Û ç 0ß (Ý ß 'Ý ß R× RÓ RÝ !ç TÑ TÝ Mß OÓ O÷0÷ 0÷1÷(÷ (÷ (÷ (÷*÷ *÷B÷ B÷ B÷ B÷ B÷ B÷ B÷ B÷ B÷ Bñ B÷/÷ /÷ /õ /÷e÷ e÷ e÷ e÷A÷ A÷ A÷ Aõ A÷)ó )õ >÷&÷ &ñ &÷[÷ [÷ [÷ [÷ [÷ [÷ [÷ [÷ [÷ [÷ [÷ [ñ [ð" 
ˆ×	Ò	˜8Ó	$€ðÛðÛô@ôð& ÷ð ó ðð  2;ñNØðNØðNØ,/ðNØCHðNàðNà+.ðNà?MôNðJ#bÙØ�Ð2ÐD[Ø5ÐAWØ ô"ðJ#bñ
 �> >Ð3CÐXnÔoðJ#bð fðJ#bñ ØÐ<Ð>NØ5ô7ðJ#bñ �< Ð/?ÐTiÔjðJ#bð ZðJ#bð Ð Ð"@Ø9Ð;QðSðJ#bñ ØÐ+Ð-?Ø7ÐJ`ôbðJ#bð">ð#J#bð&Eð'J#bð.?ð/J#bð2 fð3J#bð4 Ð#Ð%DÐFZÐ\nÐoð5J#bð6 að7J#bð8 ]ð9J#bð: Ð Ð"9Ð;NÐPaÐbð;J#bð< ið=J#bñ> ØÐ<¸oØ1ÐFdØ)Ð1DØ!Ð9NØ(BñDô	Eð?J#bðT`ðUJ#bðX3ðYJ#bð\[ð]J#bð`ðaJ#bðd hðeJ#bðf LðgJ#bðh lðiJ#bðjðkJ#bðnðoJ#bðvðwJ#bðz mð{J#bð| fð}J#bð~ gðJ#bð@ðAJ#bðD3ðEJ#bðH �^Ð%BÐDWÐYjÐkðIJ#bðJðKJ#bðR 9ðSJ#bðT añUJ#b€�ó JbñX mÐ]kÔlö0Ø€A‡D‚Dˆ!�Gò0Ð Ð,ó ñ !Ð!2Ó3Ð ÷rõ r÷
fñ fñ Ô ô
dò7Ð ð 3Ñ õ>ð 89÷ 4ð �+ð1Ñ Ð-ó õ
õ$Wõ&;õ@7õ0ð wØcñ!eÑ ñ %Ñ%BÓCò Gañ aÑ õõ*:õ
õ	]õðD 9;Ñ Ð5Ó :Ø"0 )§.¢.Ó"2Ñ õõõ õcõ_ð ð0Øð0Ø,ð0Ø?Dð0ØWZó0ó ñ0ðf à6ðØY]ñØðØHVóó ñõ<÷-ð` FK÷ T÷õõ<ðbØðbØ-0ðbà4õbõHð à3LðjØðjØ+0ójó ñjð$ `dñ4Øð4Ø-0ð4Ø9Gð4ØX\ð4à	õ4õKõ
,ð W\ñEØðEØ+ðEØ:>ðEØOSðEà	õEð\Øð\Ø-0ð\Ø9Gð\ØVdð\à	õ\õ)õ\õ
?õ÷Lð60Ñ ð
/Øð/Ø'?ð/ØNQð/àõ/õdTð ,0Ø26ñ$,Øð$,Ø3ð$,à(ð$,ð 0ð$,ð 
õ	$,õN	õ
%õõõ&Aõ
6õ$5õ
1õ
aõVõ<]ñ Ð 9Ð:Ó;Ñ Ù"Ò#\Ó]Ñ ØYÑ õFõ õ(_õñ* ˜$ÐÑ":¸DÐ!AÙ&¨Ð.Ñ1MÈtÐ0TÙ*¨DÐ1ðK3Ñ ÐGó 3õ÷"õ,%õõ,ð2$%2Ø	ˆ5ð$%2Ø˜%ð$%2Ø!'¨ð$%2Ø07¸ð$%2àˆhð$%2à'¨ð$%2à3EÀxð$%2ð ˆEð$%2ð ˜5ð$%2ð #)¨%ð$%2ð �ð	$%2ð +¨Kð	$%2ð
 �+ð$%2ð
  0°ð$%2ð ˆMð$%2ð -¨mð$%2ð >HÈñ$%2ð Ðð$%2ð "/Ð0@ð$%2ð ˆIð$%2ð -¨ið$%2ð �ð$%2ð # Gð$%2ð �ð$%2ð # Eð$%2ð �xð$%2ð "2°8ð$%2ð >CÀHð$%2ð �\ð$%2ð $0°ð$%2ð �oð$%2ð (8¸ð$%2ð KZÐ[jð$%2ð Ð+ò$%2ð .>Ð?Tð$%2ð Ð0ð$%2ð  ˆkð!$%2ð  )¨+ð!$%2ð" ˆið#$%2ð" *¨9ð#$%2ð$ �Yð%$%2ð$ !/°	ð%$%2ð& ˜-ð'$%2ð& *=¸mð'$%2ð( �ð)$%2ð(  (¨ð)$%2ð( 8KÈLð)$%2ð* �ð+$%2ð* !& ~ð+$%2ð, �<ð-$%2ð, ",¨\ò-$%2ð, <HÈð-$%2ð. 	ˆ-ð/$%2ñ. (¨ð/$%2ñ. 9JÈ=ð/$%2ñ0 ‰Hð1$%2ñ0 $¡Xð1$%2ñ2 Ñ!ð3$%2ñ2 $.Ñ/Að3$%2ñ4 Ñ'ð5$%2ñ4 *7Ñ8Jð5$%2ñ6 Ñ$ð7$%2ñ6 '6Ñ7Jð7$%2ñ8 
‰9ð9$%2ñ8 $¡Yð9$%2ñ8 1AÁ)ð9$%2ñ8 NVÑW`ð9$%2ñ: 	‰-ñ;$%2ñ: -:Ù¡ZÁÙ©Á*Ø°á¨Ù¡(Ù©óI$%2Ñ ‘>ô $2öN
ö2ö*ð& @E÷ ñ ö'ñ\ & y±*Ð&=Ó>Ñ ðØ(ðØ8EðØJWöð0  $ñ['ð '+Ø'+Ø ò['Øð['ð $ð['ð %ð	['ð
 ð['ð
 &)ö['ö@Iö
öRö
cð VZò6Øð6Ø%ð6Ø25ð6ØERð6àö6ñ fÑ öXööñ .7ó 89ó .:Ñ ™Nô :ð +˜IŸNšNÓ,Ñ Ø79Ñ Ñ4Ô 9Ù Ñ öñ( "Ø#Ø#Ø AòQ0àðQ0ð ðQ0ð ð	Q0ð
 ðQ0ð
 GJöQ0ñt #Ñ ØX\Ñ ÑUÔ \ð GKÑ ÑCÔ Jö.ö#öñ" �$Õ÷Xò Xó ñXñ2 $Ó$^Ó_Ñ ñ %ó &^ó _Ñ ò ØÑ2Ñ4JÙ6Ñ9QÑQÐfjõlò &ØÑ;Ñ=TÙ6Ñ:PÑRtÐ9uÑuØõ!ò #ØÑ<Ñ>YÙ(Ñ*>Ñ@`Ð)aÓbØõ!ò $ØÑ8Ñ:PóRâ&ØÑDÑFeógò6Ñ Ñ2ô ö&Iñ
 #*Ñ*DÈvÕ"VÑ Ù'.Ñ/IÐT_Õ'`Ñ $Ù)0Ù¨õ*9Ñ &ö0ö6öZö	_ö7ö,
Yö!ðHaØðaØ Zöaö*\ö"X÷ ð  ð&-7Ù,@×,FÒ,FÓ,H×I™y˜s D€sˆD�NŠNÑÓIð-7á(Ù5ó-7Ñ ™>ô 7ñ
 ?Ù,Ù)á7Ù4ò(6Ñ ‘nô 6ö.öb7öð& *Ø,Ø Ù(Ú^ÚQòJSÑ ÑFô Sö+ö>ð6 OSñ-à"ò-Øð-Ø*-ð-Ø>Kð-àð-à'+ö-ö`UöTöBöö$öXö!K÷P /Ñ .ß "Ñ "ß  Ð  Ý Ý ß !Ð !Ý 
Ý Ý 
ß "Ð "ðÙÑUðá,Ñ.qðñ #Ñ$aðñ ,Ñ-sð	ñ
 Ñ Yðñ "Ñ#_ðñ !Ñ"Xðñ ÑWðñ ÑQðñ ÑQðñ 'Ñ(lðñ 0Ñ1{ðñ ÑSðñ  Ñ![ðñ ÑWðñ  ÑIð!ñ" ÑRð#Ñ õ*BøðF ò ØƒEðûð ò ØƒFðüòJ0ùóN8 Js0   Èj È!j Ìj#äj(êjêjêj êj 