
    )j	                       U d 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 ddlm	Z	 ddl
mZmZmZmZmZmZ ddlmZmZmZ erddlmZ daee         ed<   d	efd
Z G d d          Z e            ZddlmZ ddlmZ ddl m!Z! ddl"m#Z#m$Z$m%Z%m&Z&  ej'        e(          Z)deded	e*fdZ+de,fdZ-da.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/d0d0d0d0d1d1d2d2d2d2d3Z/d4ee,         d	e,fd5Z0 e1            Z2e1ed6<   d7ee,         d	e*fd8Z3d7ee,         d	e*fd9Z4d:Z5d9d7ee,         d4ee,         d	e*fd;Z6	 d9d7ee,         d<ee,         d	d=fd>Z7	 d9d?d@d7ee,         d4ee,         dAe*d	ee8         fdBZ9dCe,d	e,fdDZ:dEdFdGdHdGdIdJdKdLdMdNdOdPZ;ee,e,f         edQ<   e;Z<ee,e,f         edR<   dSdTdUZ=ee,e,f         edV<    e>d%d(h          Z?e>edW<   dXdYdZd[Z@ e>h d\          ZAd]eBdz  d	eBdz  fd^ZCd9d_eBdz  d	eBfd`ZDdadbiZEd<e,dz  d	eBfdcZFdddlGmHZI d	eBfdeZJ eJ            ZKdaLe*edf<   dMZMdMZNdgZOdhZP e            diz  ZQdjZRdke,d	ee,e,f         fdlZSd<e,d	e,fdmZTd4e,d	ee*ee         f         fdnZUd4e,d	ee         fdoZVdped	e,fdqZWd:dpedse,d	e,fdtZX G du dv          ZY G dw dx          ZZ G dy dz          Z[ G d{ d|          Z\ G d} d~          Z] G d d          Z^ G d d          Z_ G d d          Z` G d d          Za G d d          Zb G d d          Zc G d d          Zdd<e,d	e*fdZe	 d9ded7e,de,d<e,dee,         d	efdZfd	eeB         fdZgd4eBd	e,fdZhd	e,fdZiddde*d	eeje,e,f                  fdZkd	eee,e,f                  fdZld	ee,         fdZmd	eee         ee,         f         fdZnd;de,d7e,d	eee         ee,         f         fdZod	e,fdZpd<de*d	eee         ee,         f         fdZqde*dee,         d	ee,         fdZrd	e,fdZsd	e,fdZtdraue,ed<   drave,ed<   drawe,ed<   draxe,ed<   draye,ed<   drdrdrdd4e,d7e,d<e,de,de,d	dfdZzd=dZ{d	eee,         ee,         ee,         f         fdZ|d	e,fdZ}d=dZ~d<e,d	dfdZd	eee         ee,         f         fdZd7e,d	eee         ee,         f         fdZd7e,d	eee         ee,         f         fdZdddddd7ee,         dee,         dee,         dee,         d	eee         ee,         f         f
dZd9de,d	eee         ee,         f         fdZdddddZdZdeee,ef                  d	ee,ef         fdZd	eej         fdZdZi Zee,e8f         ed<   i Zee,e8f         ed<   dddddddĜZd4e,d	e,fdńZd9d4e,dee8         d	dfdǄZde,d	e*fdɄZd9de,dee,         d	dfd˄Zd=d̄Zded	e*fd΄Zd	e*fdτZded	e*fdЄZded	e*fdфZded	e*fd҄Zded	e*fdӄZdede,d	e*fdՄZded	e*fdքZded	e*fdׄZd4e,d	dfd؄Zded	e*fdڄZddۜd4e,deee,ef                  d	e,fd܄Zded	ee,ef         fd݄Z	 d9de,dedeee,ef                  d	ee,         fdZdrdd4e,dede,d	e*fdZdee,         de,dee,         dee,         dee,         dee,         deee,ef                  dee,         dedee8         dee         dee         de8deBd	efdZdee,         de,dee,         dee,         dee,         dee,         dee,         dedee8         dee         dee         de8deBd	efdZd4e,d	e*fdZ	 	 d>de,de,de,d	eee         ee,         e,f         fdZ	 	 d?de,de,de,d	eee         ee,         e,f         fdZ	 d@de,de,de,d	eee         ee,         e,f         fdZ	 	 	 dAd4e,d7ee,         d<ee,         dee,         d	ee         f
dZd9deee,ef                  d	eee         ee,         f         fdZd<d7e,de*fdZdee,         d4e,d	ee,         fdZ	 	 	 	 	 	 	 	 dBd4e,d7e,de*d e*de,de,de,deee,ef                  de*d	eee         ee,         f         fdZ	 d:ddۜde,deee,ef                  d	eee         ee,         f         fdZd:ddۜde,deee,ef                  fdZdZd4e,d7ee,         d	e*fdZd4ee,         d	e,fdZ	 d9d4e,d7ee,         d	eee         ee,         f         fdZd4e,d	e*fdZd	ee,         fd	Z	 	 d;dddd
d4ee,         d7ee,         d<ee,         dee,         de*d	eee,         ee         ee,         f         fdZd	eBfdZddded7ee,         d	eBfdZi Zeejejf         ed<    ej                    ZdZddddddd4e,de*d<ee,         dee,         dee,         deee,ef                  de*d	ejfdZdddejdedee,         ded	df
dZddddddde,d7ee,         de*d<ee,         dee,         dee,         deee,ef                  de*d	eee         ee,         f         fdZd=dZded	dfdZd=dZÐd=dZded	e*fdZded ee,         d	e*fd!Zded7ee,         d ee,         d	ee,         fd"Z	 	 	 	 	 	 	 dCd4e,d7e,de*d<e,de,de,deee,ef                  de*d	eee         ee,         f         fd#ZȐd$d%iZee,e,f         ed&<   	 	 	 	 	 dDde,d4e,d7e,d<e,de,d	ee,ee,         ee,         ee,         ee,         f         fd'Zʐd(Zde,d	ee,ef         fd)Zefde,d*e8d	e8fd+Zde,d	ee,ef         fd,Z e>h d-          Zd4e,d<e,d	e*fd.Zded	efd/Z	 	 	 	 	 	 dEd4e,d7e,dedee8         dee         dee         d0e8d1eeB         d<ee,         d	eBfd2ZҐd9d3ede,d	efd4Z	 d9ddddddddddd5
de,d4e,d7e,d<e,de,deee,ef                  dede8deded0e8d1eBd	efd6Zd	e,fd7Z	 d9ddddddddddd5
de,d4e,d7e,d<e,de,deee,ef                  dede8deded0e8d1eBd	efd8ZdS (F  u  Shared auxiliary client router for side tasks.

Provides a single resolution chain so every consumer (context compression,
session search, web extraction, vision analysis, browser vision) picks up
the best available backend without duplicating fallback logic.

Resolution order for text tasks (auto mode):
  1. User's main provider + main model (used regardless of provider type —
     aggregators, direct API-key providers, native Anthropic, Codex, etc.)
  2. OpenRouter  (OPENROUTER_API_KEY)
  3. Nous Portal (~/.hermes/auth.json active provider)
  4. Custom endpoint (config.yaml model.base_url + OPENAI_API_KEY)
  5. Native Anthropic
  6. Direct API-key providers (z.ai/GLM, Kimi/Moonshot, MiniMax, MiniMax-CN)
  7. None

Resolution order for vision/multimodal tasks (auto mode):
  1. Selected main provider, if it is one of the supported vision backends below
  2. OpenRouter
  3. Nous Portal
  4. Native Anthropic
  5. Custom endpoint (for local vision models: Qwen-VL, LLaVA, Pixtral, etc.)
  6. None

Codex OAuth (ChatGPT-account auth) is intentionally NOT in either
fallback chain: OpenAI gates this endpoint behind an undocumented,
shifting model allow-list, so "just try Codex with a hardcoded model"
rots on its own.  Codex is used only when the user's main provider *is*
openai-codex (Step 1 above) or when a caller explicitly requests it with
a model (auxiliary.<task>.provider + auxiliary.<task>.model).

Per-task overrides are configured in config.yaml under the ``auxiliary:`` section
(e.g. ``auxiliary.vision.provider``, ``auxiliary.compression.model``).
Default "auto" follows the chains above.

Payment / credit exhaustion fallback:
  When a resolved provider returns HTTP 402 or a credit-related error,
  call_llm() automatically retries with the next available provider in the
  auto-detection chain.  This handles the common case where a user depletes
  their OpenRouter balance but has Codex OAuth or another provider available.
    N)Path)SimpleNamespace)AnyDictListOptionalTupleTYPE_CHECKING)urlparseparse_qs
urlunparseOpenAI_OPENAI_CLS_CACHEreturnc                  .    t           ddlm}  | a t           S )z#Import and cache ``openai.OpenAI``.Nr   r   )r   openair   )_clss    ;/home/ubuntu/.hermes/hermes-agent/agent/auxiliary_client.py_load_openai_clsr   H   s(      ))))))     c                   (    e Zd ZdZdZd Zd Zd ZdS )_OpenAIProxyzModule-level proxy that looks like the ``openai.OpenAI`` class.

    Forwards ``OpenAI(...)`` calls and ``isinstance(x, OpenAI)`` checks to the
    real SDK class, importing the SDK lazily on first use.
     c                 *     t                      |i |S N)r   )selfargskwargss      r   __call__z_OpenAIProxy.__call__Z   s    !!!426222r   c                 :    t          |t                                S r   )
isinstancer   )r   objs     r   __instancecheck__z_OpenAIProxy.__instancecheck__]   s    #/11222r   c                     dS )Nz<lazy openai.OpenAI proxy>r   r   s    r   __repr__z_OpenAIProxy.__repr__`   s    ++r   N)__name__
__module____qualname____doc__	__slots__r    r$   r'   r   r   r   r   r   Q   sR          I3 3 33 3 3, , , , ,r   r   )	load_pool)get_hermes_home)OPENROUTER_BASE_URL)base_url_host_matchesbase_url_hostname"model_forces_max_completion_tokensnormalize_proxy_env_varsr#   
maybe_typec                 F    	 t          | |          S # t          $ r Y dS w xY w)zDReturn False instead of raising when a patched symbol is not a type.F)r"   	TypeError)r#   r4   s     r   _safe_isinstancer7   n   s9    #z***   uus    
  urlc                     t          |           }|j        rWt          |                    d                    }d t	          |j                                                  D             }||fS | dfS )zNExtract query params from URL, return (clean_url, default_query dict or None). )queryc                 &    i | ]\  }}||d          S r   r   ).0kvs      r   
<dictcomp>z-_extract_url_query_params.<locals>.<dictcomp>{   s"    EEEda!QqTEEEr   N)r   r;   r   _replacer   items)r8   parsedcleanparamss       r   _extract_url_query_paramsrG   v   so    c]]F| 6???4455EEhv|&<&<&B&B&D&DEEEf}9r   Fgooglegeminizgoogle-geminizgoogle-ai-studiozx-aixaizx.aigrokglmzaizz-aizz.aizhipukimikimi-codingmoonshotzkimi-cnkimi-coding-cnzmoonshot-cnz	gmi-cloudgmigmicloudzminimax-china
minimax-cn	anthropiccopilotcopilot-acptencent-tokenhub)
minimax_cnclaudezclaude-codegithubzgithub-copilotzgithub-modelzgithub-modelszgithub-copilot-acpzcopilot-acp-agenttencenttokenhubztencent-cloudtencentmaasproviderc                    | pd                                                                 }|                    d          r4|                    dd          d                                          }|sdS |}|dk    rdS |dk    r?t	                      pd	                                                                 }|r|d
vr|}ndS t
                              ||          S )Nautocustom::   customcodexopenai-codexmainr:   >   r:   rb   ri   )striplower
startswithsplit_read_main_provider_PROVIDER_ALIASESget)r`   
normalizedsuffix	main_provs       r   _normalize_aux_providerrt      s    $f++--3355JY'' !!#q))!,2244 	8
W~V )**0b7799??AA	 	*>>>"JJ8  Z888r   OMIT_TEMPERATUREmodelc                     | pd                                                                                     dd          d         }|                    d          p|dk    S )zHTrue for any Kimi / Moonshot model that manages temperature server-side.r:   /re   zkimi-rO   rj   rk   rsplitrl   rv   bares     r   _is_kimi_modelr~      sS    KR  &&((//Q77;D??7##5tv~5r   c                     | pd                                                                                     dd          d         }|dk    S )zATrue for Arcee Trinity Large Thinking (direct or via OpenRouter).r:   rx   re   ry   ztrinity-large-thinking)rj   rk   r{   r|   s     r   _is_arcee_trinity_thinkingr      sD    KR  &&((//Q77;D+++r   g333333?c                 F   |pd                                                                 }|dk    rdS | pd                                                                                     dd          d         }|dk    p)|                    d          p|                    d	          S )
u  True for gpt-5.5 accessed through the ChatGPT Codex OAuth backend.

    Matches only the Codex OAuth route (provider ``openai-codex``), not the
    direct OpenAI API, OpenRouter, or GitHub Copilot paths — those expose a
    larger context window for the same slug and must keep the user's default
    compaction threshold. ``gpt-5.5-pro`` and dated snapshots
    (``gpt-5.5-2026-04-23``) are matched via prefix so the override tracks the
    family without re-listing every variant.
    r:   rh   Frx   re   ry   zgpt-5.5zgpt-5.5-zgpt-5.5.rz   )rv   r`   provr}   s       r   _is_codex_gpt55r      s     N!!##))++D~uKR  &&((//Q77;D9Z
 ; ;Ztz?Z?ZZr   base_urlzOptional[float] | objectc                     t          |           r"t                              d|            t          S t	          |           rdS dS )u  Return a temperature directive for models with strict contracts.

    Returns:
        ``OMIT_TEMPERATURE`` — caller must remove the ``temperature`` key so the
            provider chooses its own default.  Used for all Kimi / Moonshot
            models whose gateway selects temperature server-side.
        ``float`` — a specific value the caller must use (reserved for future
            models with fixed-temperature contracts).
        ``None`` — no override; caller should use its own default.
    z7Omitting temperature for Kimi model %r (server-managed)g      ?N)r~   loggerdebugru   r   )rv   r   s     r   _fixed_temperature_for_modelr      sJ     e  NPUVVV!%(( s4r   T)allow_codex_gpt55_autoraiser   c                Z    t          |           rdS |rt          | |          rt          S dS )uH  Return a context-compression threshold override for specific models.

    The threshold is the fraction of the model's context window that must be
    consumed before Hermes triggers summarization.  Higher values delay
    compression and preserve more raw context.

    Per-model/route overrides:
      - Arcee Trinity Large Thinking → 0.75 (preserve reasoning context).
      - gpt-5.5 on the Codex OAuth route → 0.85, because Codex caps the window
        at 272K and the default 50% trigger would compact at ~136K. Gated by
        ``allow_codex_gpt55_autoraise`` so the user can opt back down to the
        global default (the caller passes the config flag through here).

    Returns a float in (0, 1] to override the global ``compression.threshold``
    config value, or ``None`` to leave the user's config value unchanged.
    g      ?N)r   r   !_CODEX_GPT55_COMPACTION_THRESHOLD)rv   r`   r   s      r    _compression_threshold_for_modelr      s=    , "%(( t" 1uh'G'G 1004r   provider_idc                     	 ddl m}  ||           }|r|j        r|j        S n# t          $ r Y nw xY wt                              | d          S )zReturn the cheap auxiliary model for a provider.

    Reads from ProviderProfile.default_aux_model first, falling back to the
    legacy hardcoded dict for providers that predate the profiles system.
    r   get_provider_profiler:   )	providersr   default_aux_model	Exception%_API_KEY_PROVIDER_AUX_MODELS_FALLBACKrp   )r   r   _ps      r   _get_aux_model_for_providerr     s{    222222!!+.. 	("& 	(''   044["EEEs    $ 
11zgemini-3-flash-previewzglm-4.5-flashzkimi-k2-turbo-previewzstep-3.5-flashz$google/gemini-3.1-flash-lite-previewclaude-haiku-4-5-20251001zgemini-3-flashzglm-5zgoogle/gemini-3-flash-previewznemotron-3-nano:30bzhy3-preview)rI   rM   rP   stepfunrR   rS   rV   zopencode-zenzopencode-gokilocodezollama-cloudrY   r   _API_KEY_PROVIDER_AUX_MODELSz	mimo-v2.5zglm-5v-turbo)xiaomirM   _PROVIDER_VISION_MODELS_PROVIDERS_WITHOUT_VISIONz%https://hermes-agent.nousresearch.comzHermes Agentzproductivity,cli-agent)zHTTP-RefererzX-TitlezX-OpenRouter-Categories>   1onyestrueheadersc                 8   	 ddl m}m}  | |            dd          }n# t          $ r | cY S w xY wt	          |t
                    r|s| S t          | pi           }|                                D ]'\  }}|t          |          |t          |          <   (|p| S )u  Merge user-configured ``model.default_headers`` onto resolved headers.

    User values take precedence over provider/SDK defaults, mirroring the main
    agent client (``AIAgent._apply_user_default_headers``). This lets a
    ``custom`` OpenAI-compatible endpoint behind a gateway/WAF that rejects the
    OpenAI SDK's identifying headers (``User-Agent: OpenAI/Python ...``,
    ``X-Stainless-*``) override them for auxiliary calls too — otherwise the
    main turn would succeed but title/compression/vision calls to the same
    endpoint would still fail. (#40033)

    Returns the merged dict, or the original ``headers`` (possibly ``None``)
    when nothing is configured. No allocation when there are no overrides.
    r   )cfg_getload_configrv   default_headers)hermes_cli.configr   r   r   r"   dictrC   str)r   r   r   user_headersmergedkeyvalues          r   _apply_user_default_headersr   h  s    ::::::::w{{}}g7HII   lD))  '-R  F"((** & &
U=u::s3xxWs     //	or_configc                 6   t          t                    }| 8	 ddlm}  |                                di           } n# t
          $ r i } Y nw xY wt          j                            dd                                          	                                }|r
|t          v }n|                     dd          }|s|S d	|d
<   t          j                            dd                                          }|rF|                                r1t          |          }d|cxk    rdk    rn ntt          |          |d<   na|                     dd          }t          |t          t          f          r/d|cxk    rdk    r"n nt          t          |                    |d<   |S )u  Build OpenRouter headers, optionally including response-cache headers.

    Precedence for response cache: env var > config.yaml > default (enabled).

    Environment variables:
        ``HERMES_OPENROUTER_CACHE`` — truthy (``1``/``true``/``yes``/``on``)
            enables caching; ``0``/``false``/``no``/``off`` disables.
            Overrides ``openrouter.response_cache`` in config.yaml.
        ``HERMES_OPENROUTER_CACHE_TTL`` — integer seconds (1-86400).
            Overrides ``openrouter.response_cache_ttl`` in config.yaml.

    *or_config* is the ``openrouter`` section from config.yaml.  When *None*,
    falls back to reading config from disk via ``load_config()``.
    Nr   r   
openrouterHERMES_OPENROUTER_CACHEr:   response_cacheFr   zX-OpenRouter-CacheHERMES_OPENROUTER_CACHE_TTLre   iQ zX-OpenRouter-Cache-TTLresponse_cache_ttli,  )r   _OR_HEADERS_BASEr   r   rp   r   osenvironrj   rk   _TRUTHY_ENV_VALUESisdigitintr   r"   float)r   r   r   	env_cachecache_enabledenv_ttlttls          r   build_or_headersr     s    #$$G 	555555#)),;;II 	 	 	III	 
8"==CCEEKKMMI ?!%77!&6>> $*G ! jnn:B??EEGGG >?? 	=g,,CC    5     47HH01mm0#66cC<(( 	>Q#->->->->->->->->->03CHHG,-Ns   $= AAzX-BILLING-INVOKE-ORIGINHermesAgentc                 l    t          t          | pd          d          rt          t                    S i S )zIReturn NVIDIA NIM cloud attribution headers for build.nvidia.com traffic.r:   integrate.api.nvidia.com)r0   r   r   _NVIDIA_NIM_CLOUD_HEADERS)r   s    r   build_nvidia_nim_headersr     s5    SR002LMM /-...Ir   )nous_portal_tagsc                  "    dt                      iS )zReturn a fresh Nous Portal ``extra_body`` dict.

    Computed at call time so a hot-reloaded ``hermes_cli.__version__`` is
    reflected without restarting long-running processes.
    tags)_nous_portal_tagsr   r   r   _nous_extra_bodyr     s     %''((r   auxiliary_is_nousz)https://inference-api.nousresearch.com/v1zhttps://api.anthropic.comz	auth.jsonz%https://chatgpt.com/backend-api/codexaccess_tokenc                    ddd}t          | t                    r|                                 s|S 	 ddl}|                     d          }t          |          dk     r|S |d         d	t          |d                    d
z  z  z   }t          j        |                    |                    }|	                    di           	                    d          }t          |t                    r|r||d<   n# t          $ r Y nw xY w|S )u  Headers required to avoid Cloudflare 403s on chatgpt.com/backend-api/codex.

    The Cloudflare layer in front of the Codex endpoint whitelists a small set of
    first-party originators (``codex_cli_rs``, ``codex_vscode``, ``codex_sdk_ts``,
    anything starting with ``Codex``). Requests from non-residential IPs (VPS,
    server-hosted agents) that don't advertise an allowed originator are served
    a 403 with ``cf-mitigated: challenge`` regardless of auth correctness.

    We pin ``originator: codex_cli_rs`` to match the upstream codex-rs CLI, set
    ``User-Agent`` to a codex_cli_rs-shaped string (beats SDK fingerprinting),
    and extract ``ChatGPT-Account-ID`` (canonical casing, from codex-rs
    ``auth.rs``) out of the OAuth JWT's ``chatgpt_account_id`` claim.

    Malformed tokens are tolerated — we drop the account-ID header rather than
    raise, so a bad token still surfaces as an auth error (401) instead of a
    crash at client construction.
    z!codex_cli_rs/0.0.0 (Hermes Agent)codex_cli_rs)
User-Agent
originatorr   N.   re   =   zhttps://api.openai.com/authchatgpt_account_idzChatGPT-Account-ID)r"   r   rj   base64rm   lenjsonloadsurlsafe_b64decoderp   r   )r   r   r   partspayload_b64claimsacct_ids          r   _codex_cloudflare_headersr     s%   & :$ G lC(( 0B0B0D0D ""3''u::>>NAhU1X(:!;;F44[AABB**:B??CCDXYYgs## 	4 	4,3G()   Ns   -C2  BC2 2
C?>C?c                    t          | pd                                                              d          }|                    d          rzd|v sd|v r9|dt	          d                    dz   }t
                              d||           |S |dt	          d                    d	z   }t
                              d
||           |S d|v r8|                    d          r#|d	z   }t
                              d||           |S |S )u  Normalize an Anthropic-style base URL to OpenAI-compatible format.

    Some providers (MiniMax, MiniMax-CN) expose an ``/anthropic`` endpoint for
    the Anthropic Messages API and a separate ``/v1`` endpoint for OpenAI chat
    completions.  The auxiliary client uses the OpenAI SDK, so it must hit the
    ``/v1`` surface.  Passing the raw ``inference_base_url`` causes requests to
    land on ``/anthropic/chat/completions`` — a 404.
    r:   rx   
/anthropiczopen.bigmodel.cnbigmodelNz/paas/v4u0   Auxiliary client: rewrote ZAI base URL %s → %sz/v1u,   Auxiliary client: rewrote base URL %s → %sapi.kimi.com/codingu1   Auxiliary client: rewrote Kimi base URL %s → %s)r   rj   rstripendswithr   r   r   )r   r8   	rewrittens      r   _to_openai_base_urlr     s    hn"


#
#
%
%
,
,S
1
1C
||L!! 	 $$
c(9(90s<00001J>ILLKSR[\\\,3|,,,,-5	CS)TTTi!8!8 %K	H#yYYYJr   c                 R   	 t          |           }n4# t          $ r'}t                              d| |           Y d}~dS d}~ww xY w|r|                                sdS 	 d|                                fS # t          $ r'}t                              d| |           Y d}~dS d}~ww xY w)z2Return (pool_exists_for_provider, selected_entry).z0Auxiliary client: could not load pool for %s: %sN)FNTz8Auxiliary client: could not select pool entry for %s: %s)TN)r-   r   r   r   has_credentialsselect)r`   poolexcs      r   _select_pool_entryr   <  s    ""   GSVWWW{{{{{  t++-- {T[[]]""   OQY[^___zzzzzs*    
A>AA5 5
B&?B!!B&c                    	 t          |           }n4# t          $ r'}t                              d| |           Y d}~dS d}~ww xY w|r|                                sdS 	 t          |dd          }t          |          r |            }||S t          |dd          }t          |          r
 |            S n3# t          $ r&}t                              d| |           Y d}~nd}~ww xY wdS )zEBest-effort current/next pool entry without mutating selection order.z7Auxiliary client: could not load pool for %s (peek): %sNcurrentpeekz6Auxiliary client: could not peek pool entry for %s: %s)r-   r   r   r   r   getattrcallable)r`   r   r   
current_fnr   peek_fns         r   _peek_pool_entryr   L  s;   ""   NPXZ]^^^ttttt  t++-- t
^T9d33
J 	 jllG"$--G 	799	 ^ ^ ^MxY\]]]]]]]]^4s0    
A>A-B8 )B8 8
C(C##C(entryc                     | dS t          | dd           pt          | dd          }t          |pd                                          S )Nr:   runtime_api_keyr   )r   r   rj   )r   r   s     r   _pool_runtime_api_keyr   c  sN    }r %*D
1
1
WWUNTV5W5WCsyb>>!!!r   r:   fallbackc                 H   | 6t          |pd                                                              d          S t          | dd           p#t          | dd           pt          | dd           p|}t          |pd                                                              d          S )Nr:   rx   runtime_base_urlinference_base_urlr   )r   rj   r   r   )r   r   r8   s      r   _pool_runtime_base_urlr  l  s    }8>r""((**11#666 	)400 	5.55	5*d++	 	  syb>>!!((---r   c                   .    e Zd ZdZdedefdZdefdZdS )_CodexCompletionsAdapterzyDrop-in shim that accepts chat.completions.create() kwargs and
    routes them through the Codex Responses streaming API.real_clientrv   c                 "    || _         || _        d S r   )_client_model)r   r  rv   s      r   __init__z!_CodexCompletionsAdapter.__init__  s    "r   r   c                 H   ,-./01 |                     dg           }|                     d j                  }ddlm} d}g }|D ]q}|                     dd          }|                     d          pd	}	|d
k    r't	          |	t
                    r|	nt          |	          }\|                    |           r ||          }
|||
pdd	dgdd}|                     d          }|||d<   |                     d          pi }t	          |t                    ro|                     d          }t	          |t                    rE|                     d          du rn-|                     d          pd}|dk    rd}|dd|d<   dg|d<   |                     d          }|r	 dd l}ddl	m
}m} |                    t          |                    } ||          \  }} ||          \  }}n2# t          $ r%}t                              d|           Y d }~nd }~ww xY wg }|D ]}t	          |t                    r|                     di           ni }|                     d          }|sG|                    d||                     dd	          |                     d i           d!           |r||d<   g }g }d }t	          |t"          t$          f          r|dk    r|nd 11r#t'          j                    t%          1          z   nd /t+          j                    0d }d"t
          f1fd#.dI 0fd$-dI-./0fd%,	 1r=t+          j        t%          1          -          }d&|_        |                                  ,             dd'lm} t          |          }d&|d(<   d)t8          d"d f,fd*}   j        j        j        dJi |}!	  ||!|                     d          | +          }"tA          |!d,d           }#tC          |#          r	  |#             nR# t          $ r Y nFw xY wnA# tA          |!d,d           }#tC          |#          r	  |#             w # t          $ r Y w w xY ww xY w|"tE          d-          dKd.t8          d/t
          d0t8          d"t8          fd1}$tA          |"d2d           pg D ]}% |$|%d3          }&|&d4k    rB |$|%d          pg D ]2}' |$|'d3          }(|(d5v r |                     |$|'d6d	                     3V|&d7k    rU|                    tG           |$|%d8d	          dtG           |$|%dd	           |$|%d9d:          ;          <                     tA          |"d=d           })|)rtG          tA          |)d>d          p,t	          |)t                    r|)                     d>d          ndtA          |)d?d          p,t	          |)t                    r|)                     d?d          ndtA          |)d@d          p,t	          |)t                    r|)                     d@d          ndA          }nZ# t          $ rM}0$                                rtK           .                      |t          &                    dB|            d }~ww xY w||'                                 n# ||'                                 w w xY wd	(                    |          )                                pd }	tG          dC|	|pd D          }*tG          d|*|sdEndFG          }+tG          |+g||H          S )LNmessagesrv   r   )!_chat_messages_to_responses_inputzYou are a helpful assistant.roleusercontentr:   system)r  r  F)rv   instructionsinputstoretimeout
extra_body	reasoningenabledeffortmediumminimallowrb   )r  summaryzreasoning.encrypted_contentincludetools)strip_pattern_and_formatstrip_slash_enumzRAuxiliary client: failed to sanitize tool schemas for Codex/xAI Responses path: %sfunctionnamedescription
parameters)typer!  r"  r#  r   c                  ,    dt                     ddS )Nz*Codex auxiliary Responses stream exceeded z.1fzs total timeout)r   )total_timeouts   r   _timeout_messagez9_CodexCompletionsAdapter.create.<locals>._timeout_message  s    im@T@Tiiiiir   c                  n                                     t          j        dd           } t          |           r8	  |              n,# t          $ r t
                              dd           Y nw xY w	 t          j                   d S # t          $ r  t
                              dd           Y d S w xY w)Nclosez3Codex auxiliary: client close during timeout failedTexc_infoz1Codex auxiliary: cache eviction on timeout failed)setr   r  r   r   r   r   _evict_cached_client_instance)r)  r   	timed_outs    r   _close_client_on_timeoutzA_CodexCompletionsAdapter.create.<locals>._close_client_on_timeout  s    MMOOODL'488E ggEGGGG  g g gLL!VaeLfffffga-dl;;;;; a a aP[_``````as#   
A &A0/A04B
 
&B43B4c                     Lt          j                    k    r5                                s
              t                                 	 ddlm}   |             rt          d          d S # t          $ r  t          $ r Y d S w xY w)Nr   )is_interruptedz,Codex auxiliary Responses stream interrupted)time	monotonicis_setTimeoutErrortools.interruptr1  InterruptedErrorr   )r1  r/  r'  deadliner.  s    r   _check_cancelledz9_CodexCompletionsAdapter.create.<locals>._check_cancelled!  s    #(8(8H(D(D '')) /,,..."#3#3#5#5666	::::::!>## [*+YZZZ[ [#       s   A2 2B
	B
T)_consume_codex_event_streamstream_eventc                                   d S r   r   )r<  r9  s    r   _on_each_eventz7_CodexCompletionsAdapter.create.<locals>._on_each_eventG  s     ! """""r   )rv   on_eventr)  z@Codex auxiliary Responses stream did not return a final responser#   r   defaultc                     t          | |d           }|+t          | t                    r|                     ||          }||n|S r   )r   r"   r   rp   )r#   r   r@  vals       r   	_item_getz2_CodexCompletionsAdapter.create.<locals>._item_geta  sG    c3--;:c4#8#8;''#w//C!oss7:r   outputr$  message>   textoutput_textrF  function_callcall_id	argumentsz{})r!  rJ  )idr$  r   usageinput_tokensoutput_tokenstotal_tokensprompt_tokenscompletion_tokensrO  z-Codex auxiliary Responses API call failed: %s	assistant)r  r  
tool_callsstoprT  indexrE  finish_reasonchoicesrv   rL  r   Nr   r   )*rp   r  agent.codex_responses_adapterr  r"   r   appendr   copytools.schema_sanitizerr  r  deepcopylistr   r   warningr   r   r2  r3  	threadingEventTimerdaemonstartagent.codex_runtimer:  r   r  	responsescreater   r   RuntimeErrorr   r4  r5  r   canceljoinrj   )2r   r   r
  rv   r  r  replay_messagesmsgr  r  input_itemsresp_kwargsr  r  reasoning_cfgr  r  _copyr  r  _r   	convertedtfnr!  
text_partstool_calls_rawrL  timeout_timerr:  stream_kwargsr>  event_streamfinalclose_fnrC  item	item_typepartptype
resp_usagerE  choicer9  r/  r'  r8  r.  r&  s2   `                                           @@@@@@r   rj  z_CodexCompletionsAdapter.create  s	   ::j"--

7DK00 	TSSSSS502 	, 	,C7766**Dggi((.BGx*4Wc*B*BTwwG&&s++++77HH ( Ef%D%D$E	'
 '
 **Y''%,K	" ZZ--3
j$'' 	M&NN;77M-.. M $$Y//588
  +..x88DHF **!&"(#)0 0K, /L-LK	* 

7## %	1$$$$        tE{{3333E::q++E22qq   347       
 I 
 
.8D.A.AIQUU:r***rvvf~~   & #%66-#<#<"$&&r":":	" "      1'0G$ !#
$&#-gU|#D#D^STZ^>KU4>##eM&:&:::QUO%%	37	j# 	j 	j 	j 	j 	j 	j	a 	a 	a 	a 	a 	a 	a&	 	 	 	 	 	 	 	 	 X	' & )m0D0DF^ _ _'+$##%%% HGGGGG --M&*M(##s #t # # # # # #
 94<18II=IIL33 %//'22+   #<$??H%%  



$    #<$??H%%  



$    }"#efff
; ;s ; ;s ;c ; ; ; ; !$77=2  %IdF33		))!*4!;!;!Ar K K )	$ 7 7 $;;;&--iifb.I.IJJJK /11"))/$9T9b99'!0!*4!<!<&/ik4&H&H" " "+ + +    !66J '")*na"H"H #fAKJX\A]A]dJNN>1===cd&-j/1&M&M 'gBLZY]B^B^eJNN?A>>>de!(^Q!G!G "fAKJX\A]A]dJNN>1===cd    	 	 	!! @"#3#3#5#566C?LLH#NNN		 ($$&&& ($$&&&& ) ''*%%++--5 "%-
 
 

 !(6H&&L
 
 

 H
 
 
 	
s   A
G* *
H4HH7B	X1 !P " X1 
P X1 
PX1 PX1 !Q
QQ
QQQQGX1 0Z" 1
Z;AZZZ" "Z;N)	r(   r)   r*   r+   r   r   r  r   rj  r   r   r   r  r    sb        > >F 3    T
# T
 T
 T
 T
 T
 T
r   r  c                       e Zd ZdZdefdZdS )_CodexChatShimz>Wraps the adapter to provide client.chat.completions.create().adapterc                     || _         d S r   completionsr   r  s     r   r  z_CodexChatShim.__init__      "r   N)r(   r)   r*   r+   r  r  r   r   r   r  r    s6        HH# 8 # # # # # #r   r  c                   (    e Zd ZdZdedefdZd ZdS )CodexAuxiliaryClientzOpenAI-client-compatible wrapper that routes through Codex Responses API.

    Consumers can call client.chat.completions.create(**kwargs) as normal.
    Also exposes .api_key and .base_url for introspection by async wrappers.
    r  rv   c                     || _         t          ||          }t          |          | _        |j        | _        |j        | _        d S r   )_real_clientr  r  chatapi_keyr   )r   r  rv   r  s       r   r  zCodexAuxiliaryClient.__init__  s@    '*;>>"7++	"*#,r   c                 8    | j                                          d S r   )r  r)  r&   s    r   r)  zCodexAuxiliaryClient.close  s    !!!!!r   N)r(   r)   r*   r+   r   r   r  r)  r   r   r   r  r    sO         -F -3 - - - -" " " " "r   r  c                   *    e Zd ZdZdefdZdefdZdS )_AsyncCodexCompletionsAdapterzAsync version of the Codex Responses adapter.

    Wraps the sync adapter via asyncio.to_thread() so async consumers
    (web_tools, session_search) can await it as normal.
    sync_adapterc                     || _         d S r   _syncr   r  s     r   r  z&_AsyncCodexCompletionsAdapter.__init__      !


r   r   c                 J   K   dd l } |j        | j        j        fi | d {V S Nr   asyncio	to_threadr  rj  r   r   r  s      r   rj  z$_AsyncCodexCompletionsAdapter.create  A      &W&tz'8CCFCCCCCCCCCr   N)r(   r)   r*   r+   r  r  r   rj  r   r   r   r  r    s\         "%= " " " "D D D D D D Dr   r  c                       e Zd ZdefdZdS )_AsyncCodexChatShimr  c                     || _         d S r   r  r  s     r   r  z_AsyncCodexChatShim.__init__  r  r   N)r(   r)   r*   r  r  r   r   r   r  r    s0        # = # # # # # #r   r  c                       e Zd ZdZddZdS )AsyncCodexAuxiliaryClientzHAsync-compatible wrapper matching AsyncOpenAI.chat.completions.create().sync_wrapperr  c                     |j         j        }t          |          }t          |          | _         |j        | _        |j        | _        |j        | _        d S r   )r  r  r  r  r  r   r  r   r  r  async_adapters       r   r  z"AsyncCodexAuxiliaryClient.__init__  sP    #(45lCC'66	#+$- )5r   N)r  r  )r(   r)   r*   r+   r  r   r   r   r  r    s.        RR6 6 6 6 6 6r   r  c                   4    e Zd ZdZd
dededefdZdefdZd	S )_AnthropicCompletionsAdapterz<OpenAI-client-compatible adapter for Anthropic Messages API.Fr  rv   is_oauthc                 0    || _         || _        || _        d S r   )r  r  	_is_oauth)r   r  rv   r  s       r   r  z%_AnthropicCompletionsAdapter.__init__  s    "!r   r   c           	         ddl m} ddlm} |                    dg           }|                    d| j                  }|                    d          }|                    d          }|                    dd	          }|rd }	n,|                    d
          p|                    d          pd}	|                    d          }
d }t          |t                    r|}nt          |t                    rkt          |                    dd                    
                                }|dk    r*|                    di                               d          }n|dv r|} |||||	d || j                  }|
ddl m}  ||          s|
|d<    | j        j        j        di |} |d          }|                    || j                  }t#          |j        |j        |j                  }|j        }d }t-          |d          rd|j        r]t1          |j        dd          pd}t1          |j        dd          pd}t1          |j        dd          p||z   }t#          |||          }t#          d||          }t#          |g||          S ) Nr   )build_anthropic_kwargs)get_transportr
  rv   r  tool_choice_skip_zai_max_tokensF
max_tokensmax_completion_tokensi  temperaturer$  r:   r   r!  >   rb   nonerequired)rv   r
  r  r  reasoning_configr  r  _forbids_sampling_paramsanthropic_messages)strip_tool_prefix)r  rT  r  rL  rM  rN  rO  rP  rV  rY  r   )agent.anthropic_adapterr  agent.transportsr  rp   r  popr"   r   r   rk   r  r  r  r
  rj  normalize_responser   r  rT  r  rX  hasattrrL  r   )r   r   r  r  r
  rv   r  r  _skip_mtr  r  normalized_tool_choicechoice_typeanthropic_kwargsr  response
_transport_nrassistant_messagerX  rL  rQ  rR  rO  r  s                            r   rj  z#_AnthropicCompletionsAdapter.create  s!   BBBBBB222222::j"--

7DK00

7##jj// ::4e<< 	aJJL11`VZZ@W5X5X`\`Jjj//!%k3'' 	5%0""T** 	5koofb99::@@BBKj(()4R)H)H)L)LV)T)T&& <<<)4&11!!.^
 
 
 "HHHHHH++E22 >2= //4<(/CC2BCC"]#788
++ , 
 
 ,K~m
 
 

 )8W%% 	(. 	#HNNAFFK!M ' K K Pq"8>>1EEl-ZkJkL#+"3)  E !%'
 
 

 H
 
 
 	
r   NF)	r(   r)   r*   r+   r   r   boolr  rj  r   r   r   r  r    sj        FF" "C " "t " " " "
P
# P
 P
 P
 P
 P
 P
r   r  c                       e Zd ZdefdZdS )_AnthropicChatShimr  c                     || _         d S r   r  r  s     r   r  z_AnthropicChatShim.__init__;  r  r   N)r(   r)   r*   r  r  r   r   r   r  r  :  s0        # < # # # # # #r   r  c                   6    e Zd ZdZddededededef
dZd	 Zd
S )AnthropicAuxiliaryClientz@OpenAI-client-compatible wrapper over a native Anthropic client.Fr  rv   r  r   r  c                 |    || _         t          |||          }t          |          | _        || _        || _        d S )Nr  )r  r  r  r  r  r   )r   r  rv   r  r   r  r  s          r   r  z!AnthropicAuxiliaryClient.__init__B  s?    '.{EHUUU&w//	 r   c                 h    t          | j        dd           }t          |          r |             d S d S )Nr)  )r   r  r   )r   r~  s     r   r)  zAnthropicAuxiliaryClient.closeI  s?    4,gt<<H 	HJJJJJ	 	r   Nr  )	r(   r)   r*   r+   r   r   r  r  r)  r   r   r   r  r  ?  sf        JJ! !C ! !c !S !\` ! ! ! !    r   r  c                   &    e Zd ZdefdZdefdZdS )!_AsyncAnthropicCompletionsAdapterr  c                     || _         d S r   r  r  s     r   r  z*_AsyncAnthropicCompletionsAdapter.__init__P  r  r   r   c                 J   K   dd l } |j        | j        j        fi | d {V S r  r  r  s      r   rj  z(_AsyncAnthropicCompletionsAdapter.createS  r  r   N)r(   r)   r*   r  r  r   rj  r   r   r   r  r  O  sR        "%A " " " "D D D D D D Dr   r  c                       e Zd ZdefdZdS )_AsyncAnthropicChatShimr  c                     || _         d S r   r  r  s     r   r  z _AsyncAnthropicChatShim.__init__Y  r  r   N)r(   r)   r*   r  r  r   r   r   r  r  X  s0        # A # # # # # #r   r  c                       e Zd ZddZdS )AsyncAnthropicAuxiliaryClientr  r  c                     |j         j        }t          |          }t          |          | _         |j        | _        |j        | _        |j        | _        d S r   )r  r  r  r  r  r   r  r  s       r   r  z&AsyncAnthropicAuxiliaryClient.__init__^  sP    #(49,GG+M::	#+$- )5r   N)r  r  )r(   r)   r*   r  r   r   r   r  r  ]  s(        6 6 6 6 6 6r   r  c                     | pd                                                                                     d          }|sdS |                    d          rdS t	          |          }|dk    rdS |dk    rd|v rdS dS )	u  True if the endpoint at ``base_url`` speaks the Anthropic Messages
    protocol instead of OpenAI chat.completions.

    Mirrors ``hermes_cli.runtime_provider._detect_api_mode_for_url`` so the
    auxiliary client and the main agent stay in sync on transport selection.
    Covers:

    - Any URL ending in ``/anthropic`` (MiniMax, Zhipu GLM, LiteLLM proxies,
      Anthropic-compatible gateways).
    - ``api.kimi.com/coding`` (Kimi Coding Plan — the /coding route only
      speaks Claude-Code's native Anthropic shape; ``chat.completions``
      returns 404 on Anthropic-only model aliases like ``kimi-for-coding``).
    - ``api.anthropic.com`` (native Anthropic).
    r:   rx   Fr   Tapi.anthropic.comr   r   )rj   rk   r   r   r1   )r   rq   hostnames      r   #_endpoint_speaks_anthropic_messagesr  i  s     .b''))//1188==J u<(( t ,,H&&&t>!!i:&=&=t5r   
client_objr  api_modec                    t          | t                    r| S t          | t                    r| S 	 ddlm} t          | |          r| S n# t
          $ r Y nw xY w	 ddlm} t          | |          r| S n# t
          $ r Y nw xY w|r|dk    r| S |dk    pt          |          }|s| S 	 ddl	m
} n-# t
          $ r  t                              d|           | cY S w xY w	  |||          }	n5# t          $ r(}
t                              d||
           | cY d}
~
S d}
~
ww xY wt                              d	||r
|dd
         nd|pd           t          |	|||d          S )a  Rewrap a plain OpenAI client in ``AnthropicAuxiliaryClient`` when
    the endpoint actually speaks Anthropic Messages.

    This is the single chokepoint for aux-client transport correction.
    Runs at the end of every ``resolve_provider_client`` branch so that
    api_key providers (Kimi Coding Plan), the ``custom`` endpoint, and
    future /anthropic gateways all land on the right wire format
    regardless of which branch built the client.

    Returns ``client_obj`` unchanged when:

    - It's already an Anthropic/Codex/Gemini/CopilotACP wrapper.
    - The endpoint is an OpenAI-wire endpoint.
    - ``api_mode`` is explicitly set to a non-Anthropic transport.
    - The ``anthropic`` SDK is not installed (falls back to OpenAI wire).
    r   )GeminiNativeClientCopilotACPClientr  build_anthropic_clientu   Endpoint %s speaks Anthropic Messages but the anthropic SDK is not installed — falling back to OpenAI-wire (will likely 404).uT   Failed to build Anthropic client for %s (%s) — falling back to OpenAI-wire client.NzeAuxiliary transport: wrapping client in AnthropicAuxiliaryClient (model=%s, base_url=%s, api_mode=%s)<   r:   auto-detectedFr  )r7   r  r  agent.gemini_native_adapterr  ImportErroragent.copilot_acp_clientr  r  r  r  r   rb  r   r   )r  rv   r  r   r  r  r  should_wrapr  r  r   s              r   _maybe_wrap_anthropicr    sZ   0 
$<== 
$899 BBBBBBJ(:;; 		   ======J(899 		     H 444 	(( 	9.x88   BBBBBBB   O	
 	
 	

 ,,Wh??   "#+S	
 	
 	
  LL	/0x}}b(2Mo  
 $UGX   sS   A	 	
AAA3 3
B ?B 'B. .'CCC) )
D3DDDc                     t          d          \  } }| r|dS t          |dd          t          |dd          t          |dd          t          |t                    t          |dd          t          |dd          t          |d	d          t          |d
d          dd	S 	 t                                          sdS t          j        t                                                    }|	                    d          dk    rdS |	                    di           	                    di           }|	                    d          s|	                    d          sdS |S # t          $ r&}t                              d|           Y d}~dS d}~ww xY w)zRead and validate ~/.hermes/auth.json for an active Nous provider.

    Returns the provider state dict if Nous is active with tokens,
    otherwise None.
    nousNr   r:   refresh_token	agent_keyportal_base_url	client_idscope
token_typeBearerr   )	r   r  r  r   r  r  r  r  sourceactive_providerr   zCould not read Nous auth: %s)r   r   r  _NOUS_DEFAULT_BASE_URL_AUTH_JSON_PATHis_filer   r   	read_textrp   r   r   r   )pool_presentr   datar`   r   s        r   _read_nous_authr    s    -V44L% 
=4#E>2>>$UOTBB T::"8@V"W"W&u.?FF T::UGT22!%x@@

 

 
	
&&(( 	4z/33556688%&&&00488K,,00<<||K(( 	n1M1M 	4   3S999ttttts,   "E =AE AE E 
F%FFc                    ddl m} dD ]|\  }}|                     |          }t          |t                    r|                                sD |||                     d          |                     |                    r|c S }dS )z;Extract a usable Nous inference JWT from stored auth state.r   )_nous_invoke_jwt_is_usable))r  agent_key_expires_at)r   
expires_atr  )r  r	  r:   )hermes_cli.authr  rp   r"   r   rj   )r`   r  	token_key
expiry_keytokens        r   _nous_api_keyr    s    ::::::"  	: Y''%%% 	U[[]] 	%%,,w''||J//
 
 
 	
 LLL	 2r   c                  6    t          j        dt                    S )z8Resolve the Nous inference base URL from env or default.NOUS_INFERENCE_BASE_URL)r   getenvr  r   r   r   _nous_base_urlr    s    9.0FGGGr   force_refreshr  c                    	 ddl m}  |t          t          j        dd                    |           }n3# t
          $ r&}t                              d|           Y d}~dS d}~ww xY wt          |	                    d          pd	          
                                }t          |	                    d
          pd	          
                                                    d          }|r|sdS ||fS )a9  Return fresh Nous runtime credentials when available.

    This mirrors the main agent's 401 recovery path and keeps auxiliary
    clients aligned with the singleton auth store + JWT refresh flow instead of
    relying only on whatever raw tokens happen to be sitting in auth.json
    or the credential pool.
    r    resolve_nous_runtime_credentialsHERMES_NOUS_TIMEOUT_SECONDS15timeout_secondsr  z7Auxiliary Nous runtime credential resolution failed: %sNr  r:   r   rx   )r
  r  r   r   r  r   r   r   r   rp   rj   r   )r  r  credsr   r  r   s         r   _resolve_nous_runtime_apir    s   	DDDDDD00!"),I4"P"PQQ'
 
 
    NPSTTTttttt %))I&&,"--3355G599Z((.B//5577>>sCCH ( tHs   36 
A& A!!A&c            	      :   	 ddl m} m} t          d          }|r|                                rk|                                }|Tt          t          |dd          pt          |dd          pd                                          } |t          j
        dd                                                              d	          pt          j
        d
d                                                              d	          pt          t          |dd          pd                                                              d	          pDt          t          |dd          pd                                                              d	          |           }|r|r||fS n2# t          $ r%}t                              d|           Y d}~nd}~ww xY w	 ddl m}  |            }n3# t          $ r&}t                              d|           Y d}~dS d}~ww xY wt          |                    d          pd                                          }t          |                    d          pd                                                              d	          }|r|sdS ||fS )aW  Resolve a fresh xAI OAuth (api_key, base_url) for auxiliary clients.

    Prefer the credential pool, matching the main runtime/provider status
    path.  Some xAI OAuth logins live only as pool entries; falling straight
    to the singleton auth-store resolver would make auxiliary tasks such as
    compression report "no provider configured" even though ``hermes auth
    status`` shows xAI OAuth as logged in.

    Falls back to ``hermes_cli.auth``'s singleton runtime resolver for older
    auth-store-only logins. Returns ``None`` if the user is not authenticated
    with xAI Grok OAuth.
    r   )DEFAULT_XAI_OAUTH_BASE_URL _xai_validate_inference_base_url	xai-oauthNr   r   r:   HERMES_XAI_BASE_URLrx   XAI_BASE_URLr   r   )r   z9Auxiliary xAI OAuth pool credential resolution failed: %s%resolve_xai_oauth_runtime_credentialsz<Auxiliary xAI OAuth runtime credential resolution failed: %sr  )r
  r  r   r-   r   r   r   r   rj   r   r  r   r   r   r   r%  rp   )	r  r   r   r   r  r   r   r%  r  s	            r   _resolve_xai_oauth_for_auxr&  0  s   W	
 	
 	
 	
 	
 	
 	
 	

 %% 	-D((** 	-KKMME E#4d;; unb99  %''	 
 <;I3R88>>@@GGLL Wy44::<<CCCHHW75*<dCCIrJJPPRRYYZ]^^W 75*d;;ArBBHHJJQQRUVV7    -x -"H,, W W WPRUVVVVVVVVWIIIIII5577   SUXYYYttttt %))I&&,"--3355G599Z((.B//5577>>sCCH ( tHs0   FF 
G'GGG! !
H+HHc                  &   t          d          \  } }| rt          |          }|r|S 	 ddlm}  |            }|                    di           }|                    d          }t          |t                    r|                                sdS 	 ddl}|	                    d          d         }|d	t          |           d
z  z  z  }t          j        |                    |                    }	|	                    dd          }
|
r4t          j                    |
k    rt                              d|
           dS n# t"          $ r Y nw xY w|                                S # t"          $ r&}t                              d|           Y d}~dS d}~ww xY w)a  Read a valid, non-expired Codex OAuth access token from Hermes auth store.

    If a credential pool exists but currently has no selectable runtime entry
    (for example all pool slots are marked exhausted), fall back to the
    profile's auth.json token instead of hard-failing. This keeps explicit
    fallback-to-Codex working when the pool state is stale but the stored OAuth
    token is still valid.
    rh   r   )_read_codex_tokenstokensr   Nr   re   r   r   expz-Codex access token expired (exp=%s), skippingz2Could not read Codex auth for auxiliary client: %s)r   r   r
  r(  rp   r"   r   rj   r   rm   r   r   r   r   r2  r   r   r   )r  r   r  r(  r  r)  r   r   payloadr   r*  r   s               r   _read_codex_access_tokenr,  g  s    -^<<L% %e,, 	L666666!!##(B''zz.11,,, 	L4F4F4H4H 	4
	MMM"((--a0Gss7||ma/00GZ 8 8 A ABBF**UA&&C ty{{S((LcRRRt 	 	 	D	 !!###   I3OOOttttts=   A$E  B)D< ;E  <
E	E  E		E   
F*FFc                     	 ddl m} m} n+# t          $ r t                              d           Y dS w xY w|                                 D ]\  }}|j        dk    rt          |          rt                              d|           =|dk    r4	 ddl m	}  |d          sVn# t          $ r Y nw xY wt                      c S t          |          \  }}|rt          |          }|st          ||j                  p|j        }t          |          }	t!          |          pd	}
|
t                              d
|j        |
           |dk    r$ddlm}m}  ||	          r |||	          |
fc S i }t+          |	d          rddi|d<   nt+          |	d          rddlm}  |            |d<   nft+          |	d          rt1          |	          |d<   nC	 ddlm}  ||          }|r|j        rt9          |j                  |d<   n# t:          $ r Y nw xY wt=          |                    d                    }|r||d<   tA          d||	d|}tC          ||
||          }||
fc S  ||          }tE          |                    dd                    #                                }|s`tE          |                    dd                    #                                $                    d          p|j        }t          |          }	t!          |          pd	}
|
t                              d|j        |
           |dk    r$ddlm}m}  ||	          r |||	          |
fc S i }t+          |	d          rddi|d<   nt+          |	d          rddlm}  |            |d<   nft+          |	d          rt1          |	          |d<   nC	 ddlm}  ||          }|r|j        rt9          |j                  |d<   n# t:          $ r Y nw xY wt=          |                    d                    }|r||d<   tA          d||	d|}tC          ||
||          }||
fc S dS )zTry each API-key provider in PROVIDER_REGISTRY order.

    Returns (client, model) for the first provider with usable runtime
    credentials, or (None, None) if none are configured.
    r   )PROVIDER_REGISTRY$resolve_api_key_provider_credentialsz7Could not import PROVIDER_REGISTRY for API-key fallbackNNr  z2Auxiliary api-key chain: %s is unhealthy, skippingrV   )!is_provider_explicitly_configuredNz'Auxiliary text client: %s (%s) via poolrI   r  is_native_gemini_base_urlr  r   r   r   claude-code/0.1.0r   api.githubcopilot.com)copilot_default_headersr   r   r:   r   rx   zAuxiliary text client: %s (%s)r   )%r
  r.  r/  r  r   r   rC   	auth_type_is_provider_unhealthyr1  _try_anthropicr   r   r  r   r   r   r!  r  r  r3  r0   hermes_cli.modelsr7  r   r   r   r   r   r   r   rp   r   r  r   rj   r   )r.  r/  r   pconfigr1  r  r   r  raw_base_urlr   rv   r  r3  extrar7  _gpf_aux_ph_aux_merged_auxr  r  	_gpf_aux2_ph_aux2_merged_aux2s                          r   _resolve_api_key_providerrE    s   [[[[[[[[[   NOOOzz !2 7 7 9 9 a aW	))!+.. 	LLM{[[[+%%MMMMMM88EE    !#####0==e &	"+E22G 1%9STTrX_XrL*<88H/<<DE}LLBGLRWXXXh&&eeeeeeee,,X66 Y--gQQQSXXXXXE$X~>> ,8:M+N'((&x1HII EEEEEE+B+B+D+D'((&x1KLL 	+CH+M+M'((JJJJJJ&h{33G Q7#: Q378O3P3P/0    D5eii@Q6R6RSSK 7+6'(IWxII5IIG+GUG\RRGE>!!!44[AAeii	2..//5577 	599Z4455;;==DDSIIgWMg&|44+K88@D=5w|UKKK(""aaaaaaaa((22 U))'HMMMuTTTT >:: 	(46I'JE#$$"8-DEE 	AAAAAA'>'>'@'@E#$$"8-GHH 		'?'I'IE#$$GGGGGG$9[11 N 8 N/3H4L/M/ME+,   2599=N3O3OPP 	4'3E#$E8EEuEE'NN~:sB    $33B!!
B.-B.1H
HH
1O<<
P	P	explicit_api_keyc                    t          d          \  }}|r| pt          |          }|st          dd           dS t          |t                    pt          }t
                              d           t          ||t                                |pt          fS | pt          j        d          }|st          dd           dS t
                              d           t          |t          t                                |pt          fS )	Nr   r  r   r0  z%Auxiliary client: OpenRouter via poolr  r   r   OPENROUTER_API_KEYzAuxiliary client: OpenRouter)r   r   _mark_provider_unhealthyr  r/   r   r   r   r   _OPENROUTER_MODELr   r  )rF  rv   r  r   or_keyr   s         r   _try_openrouterrN    s,   ,\::L% W!A%:5%A%A 	$\r:::::)%1DEE\I\<===fx'7'9'9; ; ;<A<VEVW 	W @+?!@!@F  26666z
LL/000&+>#3#5#57 7 78=8RARS Sr   c                      t          d          \  } }| r|dS t          |          sdS t          t          j        d          pd                                          sdS dS )	z>Return a more precise OpenRouter auth failure reason for logs.r   NzOOpenRouter credential pool has no usable entries (credentials may be exhausted)z=OpenRouter credential pool entry is missing a runtime API keyrJ  r:   zOPENROUTER_API_KEY not setz&no usable OpenRouter credentials found)r   r   r   r   r  rj   )r  r   s     r    _describe_openrouter_unavailablerP    sw    ,\::L% S=dd$U++ 	SRRry-..4"55;;== ,++33r   visionc                 4   	 ddl m}  |            }|4|dk    r.t                              d|           t	          d|           dS n# t
          $ r Y nw xY wt                      }t          d          }|/|s-t                              d	           t	          dd
           dS ||rt                              d           da	t                              d           t          }	 ddlm}  ||           }|r#|}t                              d| rdnd|           n t                              d| rdnd|           n8# t
          $ r+}t                              d| rdnd||           Y d }~nd }~ww xY w||\  }	}
nt          |pi           }	|	s-t                              d           t	          dd
           dS t          |pi                     d          pt!                                                    d          }
t%          |	|
          |fS )Nr   )nous_rate_limit_remainingz?Auxiliary: skipping Nous Portal (rate-limited, resets in %.0fs)r  rH  r0  Fr  zSAuxiliary Nous client unavailable: no Nous authentication found (run: hermes auth).r  zLAuxiliary Nous: runtime JWT refresh failed; checking stored auth.json token.TzAuxiliary client: Nous Portalget_nous_recommended_aux_modelrQ  z/Auxiliary/%s: using Portal-recommended model %srQ  rF  z:Auxiliary/%s: no Portal recommendation, falling back to %szGAuxiliary/%s: recommended-models lookup failed (%s); falling back to %sz]Auxiliary Nous client unavailable: no usable inference JWT found (run: hermes auth add nous).r   rx   r4  )agent.nous_rate_guardrS  r   r   rK  r   r  r  rb  r   _NOUS_MODELr;  rU  r  r   rp   r  r   r   )rQ  rS  
_remainingr  runtimerv   rU  recommendedr   r  r   s              r   	_try_nousr\  *  s   CCCCCC..00
!j1nnLLQ   %V<<<<:    D'e<<<Gt"	
 	
 	
 	!R0000z4	
 	
 	

 
LL0111 E
DDDDDD44FCCC 
	ELLA".   
 LLL".    
 
 
!*HHFC	
 	
 	
 	
 	
 	
 	
 	

 #
++ 	NN/   %V4444:
''(<==QAQAQRRYYZ]^^	
 	
 	
 	 s+   AA	 	
AA*AE 
E7!E22E7stale_modelc                    |pd                                                                 }d}	 ddlm}  || d          }n8# t          $ r+}t
                              d|t                     Y d}~nd}~ww xY w|r,|                                                                 |k    r|S t                                                                           |k    rt          S dS )u  Re-fetch the Nous Portal's recommended model after a stale-model 404.

    Long-lived processes (gateway, watchers) cache the Portal's
    ``recommended-models`` payload for 10 minutes and, in practice, can pin a
    model for the whole process lifetime. When that model is later dropped from
    the Nous → OpenRouter catalog, every auxiliary call 404s with
    "model does not exist". This forces a fresh Portal fetch and returns a
    model name to retry with:

      * the Portal's current recommendation for the task, if it differs from
        the model that just failed; otherwise
      * ``_NOUS_MODEL`` (google/gemini-3-flash-preview), the known-good default,
        if it too differs from the failed model.

    Returns ``None`` when no usable alternative is available (e.g. the Portal
    still recommends the exact model that just 404'd and the default also
    matches it) — callers should then let the original error propagate.
    r:   Nr   rT  T)rQ  r  z<Nous recommended-model refresh failed (%s); using default %s)rj   rk   r;  rU  r   r   r   rX  )rQ  r]  stalefreshrU  r   s         r   _refresh_nous_recommended_modelra  ~  s   * B%%''--//EE
DDDDDD..fDQQQ 
 
 
J	
 	
 	
 	
 	
 	
 	
 	


  $$&&%//   ""e++4s   A   
A5
!A00A5c                  H   t           } t          | t                    r(|                                 r|                                 S 	 ddlm}  |            }|                    di           }t          |t                    r(|                                r|                                S t          |t                    rS|                    dd          }t          |t                    r(|                                r|                                S n# t          $ r Y nw xY wdS )a6  Read the user's configured main model from config.yaml.

    config.yaml model.default is the single source of truth for the active
    model. Environment variables are no longer consulted.

    Runtime override: when an AIAgent is active with a CLI/gateway-provided
    model that differs from config.yaml, ``set_runtime_main()`` records the
    override in a process-local global. This is consulted FIRST so tools
    that gate on "the active main model" (e.g. ``vision_analyze``'s native
    fast path) see the live runtime, not the persisted config default.
    r   r   rv   r@  r:   )	_RUNTIME_MAIN_MODELr"   r   rj   r   r   rp   r   r   )overrider   cfg	model_cfgr@  s        r   _read_main_modelrg    s    #H(C    X^^%5%5  ~~111111kmmGGGR((	i%% 	%)//*;*; 	%??$$$i&& 	'mmIr22G'3'' 'GMMOO '}}&   2s   A"D )A'D 
DDc                     t           } t          | t                    r:|                                 r&|                                                                 S 	 ddlm}  |            }|                    di           }t          |t                    re|                    dd          }t          |t                    r:|                                r&|                                                                S n# t          $ r Y nw xY wdS )u  Read the user's configured main provider from config.yaml.

    Returns the lowercase provider id (e.g. "alibaba", "openrouter") or ""
    if not configured.

    Runtime override: see ``_read_main_model`` — same mechanism for the
    provider half of the runtime tuple.
    r   r   rv   r`   r:   )
_RUNTIME_MAIN_PROVIDERr"   r   rj   rk   r   r   rp   r   r   )rd  r   re  rf  r`   s        r   rn   rn     s    &H(C   (X^^%5%5 (~~%%'''	111111kmmGGGR((	i&& 	0 }}Z44H(C(( 0X^^-=-= 0~~''--///   2s   BC9 9
DDri  rc  _RUNTIME_MAIN_BASE_URL_RUNTIME_MAIN_API_KEY_RUNTIME_MAIN_API_MODE)r   r  r  c                0   | pd                                                                 a|pd                                 a|pd                                 at          |t                    r|                                 nda|pd                                 adS )a"  Record the live runtime provider/model/credentials for the current AIAgent.

    Called by ``run_agent.AIAgent._sync_runtime_main_for_aux_routing`` (or
    equivalent setter) at the top of each turn so that
    ``_read_main_provider`` / ``_read_main_model`` reflect CLI/gateway
    overrides instead of the stale config.yaml default.

    For ``custom:`` providers, ``base_url`` and ``api_key`` must also be
    recorded so that ``_resolve_auto`` can construct a valid client in
    Step 1 instead of falling through to the aggregator chain.
    r:   N)	rj   rk   ri  rc  rj  r"   r   rk  rl  )r`   rv   r   r  r  s        r   set_runtime_mainrn    s    * 'n"3355;;== ;B--//&n"3355/9'3/G/GOGMMOOOR&n"3355r   c                      da dadadadadS )z1Clear the runtime override (e.g. on session end).r:   N)ri  rc  rj  rk  rl  r   r   r   clear_runtime_mainrp    s(      r   c                     	 ddl m}   | d          }n4# t          $ r'}t                              d|           d}Y d}~nd}~ww xY wt          |t                    sjt          j        dd          	                                
                    d	          }t          j        d
d          	                                }|sdS ||d}|                    d          }|                    d          }|                    d          }t          |t                    r|	                                sdS |	                                
                    d	          }t          |d          rdS t          |t                    r|	                                sd}t          |t                    r|	                                sd}||	                                |fS )zResolve the active custom/main endpoint the same way the main CLI does.

    This covers both env-driven OPENAI_BASE_URL setups and config-saved custom
    endpoints where the base URL lives in config.yaml instead of the live
    environment.
    r   )resolve_runtime_providerrf   )	requestedz6Auxiliary client: custom runtime resolution failed: %sNOPENAI_BASE_URLr:   rx   OPENAI_API_KEYNNN)r   r  r   r  r  openrouter.aino-key-required)hermes_cli.runtime_providerrr  r   r   r   r"   r   r   r  rj   r   rp   r   r0   )rr  rZ  r   openai_base
openai_keycustom_base
custom_keycustom_modes           r   _resolve_custom_runtimer    s   HHHHHH**X>>>   MsSSS gt$$ 
i 1266<<>>EEcJJY/44::<<
 	$###!
 

 ++j))KY''J++j))Kk3''  {/@/@/B/B  ##%%,,S11K[/::     j#&& 'j.>.>.@.@ '&
k3'' {/@/@/B/B 
((**K77s    
AAAc                  .    t                      \  } }}| pdS )Nr:   )r  )r|  rt  s     r   _current_custom_base_urlr  @  s    /11KA"r   c            	      D   ddl m}  t                       dD ]}t          t          j                            |          pd                                          }|sE	  | |          }|j        r|j	        }`# t          $ r}t          d| d|d          |d}~ww xY wdS )	a  Fail fast with a clear error when proxy env vars have malformed URLs.

    Common cause: shell config (e.g. .zshrc) with a typo like
    ``export HTTP_PROXY=http://127.0.0.1:6153export NEXT_VAR=...``
    which concatenates 'export' into the port number.  Without this
    check the OpenAI/httpx client raises a cryptic ``Invalid port``
    error that doesn't name the offending env var.
    r   r   )HTTPS_PROXY
HTTP_PROXY	ALL_PROXYhttps_proxy
http_proxy	all_proxyr:   z%Malformed proxy environment variable r   z1. Fix or unset your proxy settings and try again.N)urllib.parser   r3   r   r   r   rp   rj   schemeport
ValueErrorrk  )r   r   r   rD   rt  r   s         r   _validate_proxy_env_urlsr  E  s     &%%%%%:  BJNN3''-2..4466 		Xe__F}  K 	 	 	B B Be B B B  	 s   A77
BBBc                    ddl m} t          | pd                                          }|r|                    d          rdS 	  ||          }|j        dv r	|j        }dS dS # t          $ r}t          d|d          |d}~ww xY w)	zEReject obviously broken custom endpoint URLs before they reach httpx.r   r  r:   zacp://N>   httphttpszMalformed custom endpoint URL: zJ. Run `hermes setup` or `hermes model` and enter a valid http(s) base URL.)	r  r   r   rj   rl   r  r  r  rk  )r   r   	candidaterD   rt  r   s         r   _validate_base_urlr  b  s    %%%%%%HN##))++I 	,,X66 )$$=---AAA .-   Wi W W W
 
 	s   A# #
B-BBc                     t                      } t          |           dk    r| \  }}d }n| \  }}}|r|sdS |                                                    t                                                    rdS t                      pd}t                              d||pd           t          |          \  }}|rd|ini }t          d           }|r||d<   |dk    r!t          d||d	|}	t          |	|          |fS |d
k    re	 ddlm}
  |
||          }	n;# t          $ r. t                              d           t          d||d	||fcY S w xY wt!          |	|||d          |fS t          d||d	|}t#          |||||          }||fS )Nr   r0  gpt-4o-miniz3Auxiliary client: custom endpoint (%s, api_mode=%s)chat_completionsdefault_queryr   codex_responsesr4  r  r   r  u|   Custom endpoint declares api_mode=anthropic_messages but the anthropic SDK is not installed — falling back to OpenAI-wire.Fr  r   )r  r   rk   rl   _CODEX_AUX_BASE_URLrg  r   r   rG   r   r   r  r  r  r  rb  r  r  )rZ  r|  r}  r~  rv   _clean_base_dq_extra_custom_headersr  r  _fallback_clients               r   _try_custom_endpointr  t  s9   %''G
7||q")Z/6,Z j z%%&9&?&?&A&ABB z/-E
LLF{Op^pqqq0==K'*2os##F
 2$77O 4$3 !'''PZ+PPPP#K77>>***	UFFFFFF00[IIKK 	U 	U 	UNNR   M*{MMfMMuTTTT	U %[%[[`aaa
 	
 Qj;QQ&QQ,%[+  U""s   D 5EEc                     | st                               d           dS t                      }|dS |\  }}t                               d|            t	          ||          }t          ||           | fS )u  Build a CodexAuxiliaryClient for an xAI Grok OAuth-authenticated session.

    xAI's ``/v1/responses`` endpoint speaks the OpenAI Responses API, so we
    wrap a plain ``OpenAI`` client in ``CodexAuxiliaryClient`` to translate
    ``chat.completions.create()`` calls into ``responses.stream()`` requests.

    The caller must pass an explicit model — pinning a default for Grok
    would silently rot when xAI's allowlist drifts.  Returns ``(None, None)``
    when the user has not authenticated with xAI Grok OAuth.
    zuAuxiliary client: xai-oauth requested without a model; pass model explicitly (auxiliary.<task>.model in config.yaml).r0  Nz2Auxiliary client: xAI OAuth (%s via Responses API)r4  )r   rb  r&  r   r   r  )rv   resolvedr  r   r  s        r   _build_xai_oauth_aux_clientr    s      M	
 	
 	
 z)++Hz GX
LLEuMMM8<<<KU33U::r   c                    | st                               d           dS t          d          \  }}|rHt          |          }|rt	          |t
                    pt
          }n3t                      }|sdS t
          }nt                      }|sdS t
          }t                               d|            t          ||t          |                    }t          ||           | fS )a  Build a CodexAuxiliaryClient for an explicitly-requested model.

    There is no auto-selection of the Codex model: the ChatGPT-account
    Codex endpoint's accepted model list is an undocumented, drifting
    allow-list, so any hardcoded default we pick goes stale.  The caller
    is responsible for passing the model (e.g. from the user's own
    ``model.model`` or ``auxiliary.<task>.model`` config).

    Returns (None, None) when no Codex OAuth token is available.
    zxAuxiliary client: openai-codex requested without a model; pass model explicitly (auxiliary.<task>.model in config.yaml).r0  rh   z4Auxiliary client: Codex OAuth (%s via Responses API)rI  )r   rb  r   r   r  r  r,  r   r   r   r  )rv   r  r   codex_tokenr   r  s         r   _build_codex_clientr    s     M	
 	
 	
 z,^<<L% '+E22 	+-e5HII`M`HH244K "!z*HH.00 	:&
LLGOOO1+>>  K
  U33U::r   rv   rF  explicit_base_urlr  r  c                 l   	 ddl m} ddlm} ddlm} n# t          $ r Y dS w xY w	  |            }t          |t                    r|	                    d          ni }t          |t                    si }n# t          $ r i }Y nw xY w	  |d||||           }	n\# |$ r&}
t                              d	|
           Y d
}
~
dS d
}
~
wt          $ r&}
t                              d|
           Y d
}
~
dS d
}
~
ww xY w|		                    d          }t          |		                    dd          pd          }|p|		                    d          pd}t          |          st          |          nd}|r|sdS t!          | p#t          |	                    d          pd          d          }|s1t                              d| |	                    d                     dS i }t#          |          \  }}|r||d<   t%          d||d|}|dk    rt'          ||          |fS |dk    rt)          |||||          |fS ||fS )u  Resolve an Azure Foundry auxiliary client via the runtime resolver.

    Mirrors the ``_try_anthropic`` / ``_try_nous`` shape but delegates to
    :func:`hermes_cli.runtime_provider._resolve_azure_foundry_runtime` —
    the same resolver the main agent uses — so:

    * ``auth_mode: api_key`` (default) gets the static
      ``AZURE_FOUNDRY_API_KEY`` string.
    * ``auth_mode: entra_id`` gets a callable bearer-token provider
      (``Callable[[], str]`` from
      :mod:`agent.azure_identity_adapter`).
    * Per-model ``api_mode`` auto-routing for GPT-5.x / o-series /
      codex models works.
    * ``model.entra.{tenant_id,client_id,authority,scope}`` config
      fields propagate.
    * Non-default ``model.base_url`` overrides are honored.

    The OpenAI SDK accepts both shapes for ``api_key`` so the caller
    can forward the result without coercion.

    Returns ``(client, model)`` or ``(None, None)`` on failure.
    r   )_resolve_azure_foundry_runtime)	AuthErrorr   r0  rv   azure-foundry)requested_providerrf  rF  r  target_modelzAuxiliary azure-foundry: %sNz)Auxiliary azure-foundry runtime error: %sr  r   r:   r  r  Tr@  zAAuxiliary azure-foundry: no model resolved (model=%r, default=%r)r  r4  r  r  r   )ry  r  r
  r  r   r   r  r"   r   rp   r   r   r   r   r   r  _normalize_resolved_modelrG   r   r  r  )rv   rF  r  r  r  r  r   re  rf  rZ  r   r  r   runtime_api_mode_has_keyfinal_modelr>  r  r  clients                       r   _try_azure_foundryr    s   :NNNNNN------1111111   zzkmm(23(=(=ECGGG$$$2	)T** 	I   			00.-/
 
 
    2C888zzzzz   @#FFFzzzzz kk)$$G7;;z2..4"55HP7;;z#:#:P>P
 %-W$5$5?tG}}}4H 8 z+4Y]]9--344 K   	O9==++	
 	
 	
 z
 E0::K
 %!$oCGkCCUCCF,,, $FK88+EE///
 %K&
 
  	 ;sB    
##AA5 5BBB C2B??C2C--C2c                    	 ddl m}m} n# t          $ r Y dS w xY wt	          d          \  }}|r|dS | pt          |          }nd }| p	 |            }|sdS |rt          |t                    nt          }	 ddlm	}  |            }|
                    d          }	t          |	t                    rt          |	
                    d          pd                                                                          }
|
dk    r@|	
                    d	          pd                                                    d
          }|r|}n# t"          $ r Y nw xY wddl m}  ||          }t'          d          pd}t(                              d|||           	  |||          }n# t          $ r Y dS w xY wt-          |||||          |fS )Nr   )r  resolve_anthropic_tokenr0  rV   r   rv   r`   r:   r   rx   )_is_oauth_tokenr   z8Auxiliary client: Anthropic native (%s) at %s (oauth=%s)r  )r  r  r  r  r   r   r  _ANTHROPIC_DEFAULT_BASE_URLr   r   rp   r"   r   r   rj   rk   r   r   r  r   r   r   r  )rF  r  r  r  r   r  r   r   re  rf  cfg_providercfg_base_urlr  r  rv   r  s                   r   r:  r:  \  sZ   [[[[[[[[[   zz -[99L% >=: @$9%$@$@ =$;$;$=$= z
 NZz%e-HIII_zH111111kmmGGG$$	i&& 	,y}}Z88>B??EEGGMMOOL{** )j 9 9 ?RFFHHOOPSTT ,+H    877777u%%H'44S8SE
LLKUT\^fggg,,UH==    zz	
 $KxRZ[[[]bbbs1    
7CE   
EEF 
F+*F+r   r  local/customapi-keyrN  r\  r  rE  )r`   rv   r   r  r  	auth_modemain_runtimec                    t          | t                    si S i }t          D ]}|                     |          }|dk    r*t	          |          rt          |t
                    s|||<   Gt          |t
                    r+|                                r|                                ||<   |                    d          }t          |t
                    r|                                |d<   |S )u  Return a sanitized copy of a live main-runtime override.

    Most fields are stripped strings. ``api_key`` may legitimately be a
    zero-arg callable (Azure Foundry Entra ID token provider) — preserve
    those as-is so auxiliary clients inherit the same authentication
    surface as the main agent. The OpenAI SDK accepts ``Callable[[], str]``
    for ``api_key`` and calls it before every request.
    r  r`   )r"   r   _MAIN_RUNTIME_FIELDSrp   r   r   rj   rk   )r  rq   fieldr   r`   s        r   _normalize_main_runtimer    s     lD)) 	!#J% . .  ''I(5//*UC:P:P %JueS!! 	.ekkmm 	. %Ju~~j))H(C   2!)!1!1
:r   c                  F    dt           fdt          fdt          fdt          fgS )aB  Return the ordered provider detection chain.

    Built at call time (not module level) so that test patches
    on the ``_try_*`` functions are picked up correctly.

    NOTE: ``openai-codex`` is deliberately NOT in this chain.  The
    ChatGPT-account Codex endpoint only accepts a shifting, undocumented
    allow-list of model IDs, so falling back to it with a guessed model
    fails more often than not.  Codex is used only when the user's main
    provider *is* openai-codex (see Step 1 of ``_resolve_auto``) or when
    a caller explicitly requests it with a model.
    r   r  r  r  r  r   r   r   _get_provider_chainr    s0     
'		-.	-.	 r   X  _aux_unhealthy_until_aux_unhealthy_logged_atrh   )r   r  rf   r  rh   rg   c                     | sdS t          |                                                                           }t                              ||          S )a  Normalize a resolved_provider value to a chain label used by
    ``_get_provider_chain()``. Falls back to the lowercased input for
    direct API-key providers (deepseek, alibaba, minimax, etc.) which
    each report their own provider name from the api-key chain.
    r:   )r   rj   rk   _AUX_UNHEALTHY_LABEL_ALIASESrp   )r`   ps     r   _normalize_chain_labelr    sJ      rH##%%A'++Aq111r   r   c                 .   t          |           }|sdS t          j                    ||nt          z   }|t          |<   t                              d|t          ||nt                    t          j        dt          j        |                               dS )zMark ``provider`` as recently-402'd, hidden from chain iteration
    until the TTL expires. Called from the payment-fallback branches in
    ``call_llm`` and ``acall_llm`` after a confirmed payment error.
    NzsAuxiliary: marking %s unhealthy for %ds (payment / credit error). Subsequent auxiliary calls will skip it until %s.z%H:%M:%S)	r  r2  _AUX_UNHEALTHY_TTL_SECONDSr  r   rb  r   strftime	localtime)r`   r   labelr	  s       r   rK  rK    s    
 #8,,E s<VWJ",
NN	<3?CC(BCCj$."<"<==    r   r  c                     | sdS t                               |           }|dS t          j                    |k    r8t                               | d           t                              | d           dS dS )zTrue iff ``label`` is in the unhealthy cache and the TTL hasn't expired.
    Lazily evicts expired entries so the cache stays small.
    FNT)r  rp   r2  r  r  )r  r	  s     r   r9  r9  		  sv      u%))%00Juy{{j    --- $$UD111u4r   taskc                 <   t          j                     }t                              | d          }||z
  dk    rd|t          | <   t                              | |          }t                              d|pd| t          dt          ||z
                                 dS dS )zEmit a single info-level log per minute when we skip an unhealthy
    provider. Avoids spamming the log on bursty sessions while still
    giving the user a trail.
    g        r  zIAuxiliary %s: skipping %s (recently returned payment error, retry in %ds)callr   N)r2  r  rp   r  r   infomaxr   )r  r  nowlastr	  s        r   _log_skip_unhealthyr  	  s    
 )++C#''s33D
TzR*- ')--eS99
WNFE3q#j3.>*?*?#@#@	
 	
 	
 	
 	
 r   c                  j    t                                            t                                           dS )zvClear the unhealthy cache. Used by tests and by a future explicit
    user trigger (e.g. ``hermes config aux reset``).N)r  clearr  r   r   r   _reset_aux_unhealthy_cacher  )	  s.        ""$$$$$r   r   c                     t          | dd          }|dk    rdS t          |                                           |dv rt          fddD                       rdS dS )	u
  Detect payment/credit/quota exhaustion errors.

    Returns True for HTTP 402 (Payment Required) and for 429/other errors
    whose message indicates billing exhaustion or daily quota exhaustion
    rather than transient rate limiting.

    Daily token quota errors (e.g. Bedrock "Too many tokens per day",
    Vertex AI "quota exceeded") are functionally equivalent to credit
    exhaustion — the provider cannot serve the request until the quota
    resets — and should trigger the same provider-fallback logic.
    status_codeN  T>   Nr      c              3       K   | ]}|v V  	d S r   r   r>   kw	err_lowers     r   	<genexpr>z$_is_payment_error.<locals>.<genexpr>E	  s7        2rY      r   )creditsinsufficient fundscan only affordbillingpayment requiredout of fundsrun out of fundsbalance_depletedno usable credits model_not_supported_on_free_tiernot available on the free tierzquota exceededquota_exceededztoo many tokens per dayzdaily limitztokens per dayzdaily quotazresource exhaustedzweekly usage limitzweekly limitFr   r   rk   anyr   statusr  s     @r   _is_payment_errorr  0	  s     S-..F}}tC  I
 &&&     *
      	 45r   c                      	 ddl m}   | d          }|j        du S # t          $ r&}t                              d|           Y d}~dS d}~ww xY w)zMReturn True only when the fresh Nous account API says paid access is allowed.r   )get_nous_portal_account_infoT)force_freshz8Auxiliary Nous paid-entitlement refresh check failed: %sNF)hermes_cli.nous_accountr  paid_service_accessr   r   r   )r  account_infor   s      r   *_nous_portal_account_has_fresh_paid_accessr  X	  s|    HHHHHH33EEE/477   OQTUUUuuuuus    
AAAc                     t          | dd          }t          |                                           t          |           j        dk    rdS |dk    r:t          fddD                       rdS t          fdd	D                       sdS d
S )aH  Detect rate-limit errors that warrant provider fallback.

    Returns True for HTTP 429 errors whose message indicates rate limiting
    (as opposed to billing/quota exhaustion, which _is_payment_error handles).
    Also catches OpenAI SDK RateLimitError instances that may not set
    .status_code on the exception object.
    r  NRateLimitErrorTr  c              3       K   | ]}|v V  	d S r   r   r  s     r   r  z'_is_rate_limit_error.<locals>.<genexpr>w	  s7        2rY      r   )
rate limit
rate_limitztoo many requestsz	try againzretry afterz	resets inc              3       K   | ]}|v V  	d S r   r   r  s     r   r  z'_is_rate_limit_error.<locals>.<genexpr>}	  s7        r2?      r   )r  r  r  r  r  r  r  r  r  r  r  F)r   r   rk   r$  r(   r  r  s     @r   _is_rate_limit_errorr  d	  s     S-..FC  I Cyy---t}}      *
      	 4     .
      	 45r   c                 D   	 ddl m}m} t          | ||f          rdS n# t          $ r Y nw xY wt          |           j        t          fddD                       rdS t          |           	                                t          fddD                       rdS dS )	aE  Detect connection/network errors that warrant provider fallback.

    Returns True for errors indicating the provider endpoint is unreachable
    (DNS failure, connection refused, TLS errors, timeouts).  These are
    distinct from API errors (4xx/5xx) which indicate the provider IS
    reachable but returned an error.
    r   )APIConnectionErrorAPITimeoutErrorTc              3       K   | ]}|v V  	d S r   r   )r>   r  err_types     r   r  z'_is_connection_error.<locals>.<genexpr>	  s'      
L
Lb2>
L
L
L
L
L
Lr   )
ConnectionTimeoutDNSSSLc              3       K   | ]}|v V  	d S r   r   r  s     r   r  z'_is_connection_error.<locals>.<genexpr>	  s7        r2?      r   )zconnection refusedzname or service not knownzno route to hostznetwork is unreachablez	timed outzconnection resetzincomplete chunked readzpeer closed connectionzresponse ended prematurelyzunexpected eofremoteprotocolerrorlocalprotocolerrorF)
r   r  r  r"   r  r$  r(   r  r   rk   )r   r  r  r  r
  s      @@r   _is_connection_errorr  	  s    >>>>>>>>c.@AA 	4	    Cyy!H

L
L
L
L$K
L
L
LLL tC  I
     &       t5s   ! 
..c                     t          |           rdS t          | dd          pt          t          | dd          dd          }t          |t                    o|dk    pd|cxk    odk     nc S )a-  Return True for a one-off transport blip worth retrying ONCE on the
    same provider before any provider/model fallback.

    Covers connection/streaming-close errors (via the canonical
    ``_is_connection_error`` detector, shared so the two cannot drift) plus a
    pure 5xx/408 HTTP status. Deliberately narrow: this is the "retry the
    same target once" gate, distinct from ``_is_payment_error`` /
    ``_is_auth_error`` / ``_is_rate_limit_error`` which the except-chain
    handles by switching provider, refreshing creds, or rotating the pool.
    Tr  Nr  i  i  r  )r  r   r"   r   )r   r  s     r   _is_transient_transport_errorr  	  s     C   tS-.. 'Z&&t3 3F fc""M#(L9L9L9L9L9L9L9L9LMr   c                    t          | dd          }|dk    rdS t          |                                           }d|v s(dt          |           j                                        v rdS |dk    rd|v rdS d	|v rd|v rdS d
S )zCDetect auth failures that should trigger provider-specific refresh.r  N  Tzerror code: 401authenticationerrori  zbad-credentialsunauthenticatedF)r   r   rk   r$  r(   r  s      r   _is_auth_errorr  	  s    S-..F}}tC  II%%)>$s))BTBZBZB\B\)\)\t }}*i77tI%%*;y*H*Ht5r   paramc                     |pd                                 }|sdS t          |                                            |vrdS t          fddD                       S )a/  Detect provider 400s for an unsupported request parameter.

    Different OpenAI-compatible endpoints phrase the same class of error a few
    ways: ``Unsupported parameter: X``, ``unsupported_parameter`` with a
    ``param`` field, ``X is not supported``, ``unknown parameter: X``,
    ``unrecognized request argument: X``.  We match on both the parameter
    name and a generic "unsupported/unknown/unrecognized parameter" marker so
    call sites can reactively retry without the offending key instead of
    surfacing a noisy auxiliary failure.

    Generalizes the temperature-specific detector that originally shipped
    with PR #15621 so the same retry strategy can cover ``max_tokens``,
    ``seed``, ``top_p``, and any future quirk. Credit @nicholasrae (PR #15416)
    for the generalization pattern.
    r:   Fc              3       K   | ]}|v V  	d S r   r   )r>   markerr  s     r   r  z2_is_unsupported_parameter_error.<locals>.<genexpr>	  s8       	 	vv" 	 	 	 	 	 	r   )zunsupported parameterunsupported_parameterznot supportedzdoes not supportzunknown parameterzunrecognized request argumentzunrecognized parameterzinvalid parameter)rk   r   r  )r   r  param_lowerr  s      @r   _is_unsupported_parameter_errorr   	  s      ;B%%''K uC  I)##u 	 	 	 	 	2 	 	 	 	 	 	r   c                 "    t          | d          S )zBack-compat wrapper: detect API errors where the model rejects ``temperature``.

    Delegates to :func:`_is_unsupported_parameter_error`; kept as a separate
    public symbol because existing tests and call sites import it by name.
    r  )r   )r   s    r   !_is_unsupported_temperature_errorr"  	  s     +3>>>r   c                     t          | dd          }t          |                                           t          fddD                       rdS |dvrdS t          fddD                       S )	u!  Detect "the requested model doesn't exist" errors (404 / invalid model).

    This fires when a resolved model name is no longer served by the endpoint
    — most commonly when a long-lived process pinned a Portal-recommended model
    that has since been dropped from the Nous → OpenRouter catalog. The Nous
    proxy returns 404 with a body like::

        Model 'gpt-5.4-mini' not found. The requested model does not exist
        in our configuration or OpenRouter catalog.

    Distinct from :func:`_is_payment_error` (which also matches some 404s for
    free-tier/credit language) — this one keys on "does not exist / not found /
    not a valid model" phrasing, and explicitly excludes the billing keywords
    that the payment path already owns so the two predicates don't overlap.
    r  Nc              3       K   | ]}|v V  	d S r   r   r  s     r   r  z,_is_model_not_found_error.<locals>.<genexpr>
  s7        r2?      r   )	r  r  r  r  r  r  z	free tierz	free-tierr  F>   N  r  c              3       K   | ]}|v V  	d S r   r   r  s     r   r  z,_is_model_not_found_error.<locals>.<genexpr>
  s7       
 
2rY 
 
 
 
 
 
r   )	zmodel does not existz#does not exist in our configurationzopenrouter catalogzis not a valid modelzno such modelzmodel not foundzthe model `model_not_foundzunknown modelr  r  s     @r   _is_model_not_found_errorr(  	  s      S-..FC  I
     &      
 u%%%u 
 
 
 
 
* 
 
 
 
 
 
r   c                    t          |           t          5  fdt          D             }|D ]}t                              |d          d         }|Kt	          |           	 t          |dd          }t          |          r
 |             n# t          $ r Y nw xY wt                              |d           	 ddd           dS # 1 swxY w Y   dS )zEDrop cached auxiliary clients for a provider so fresh creds are used.c                 `    g | ]*}t          t          |d                              k    (|+S r=   )rt   r   )r>   r   rq   s     r   
<listcomp>z)_evict_cached_clients.<locals>.<listcomp>+
  s@     
 
 
&s3q6{{33zAA AAAr   rv  r   Nr)  )	rt   _client_cache_lock_client_cacherp   _force_close_async_httpxr   r   r   r  )r`   
stale_keysr   r  r~  rq   s        @r   _evict_cached_clientsr0  '
  sR   (22J	 ) )
 
 
 
(
 
 

  
	) 
	)C"&&s,>??BF!(000&vw==H)) # 


    Dc4((((
	)) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )s6   A
C#*BC
BCBCCCtargetc                 :   | dS d}t           5  t          t                                                    D ]M}t                              |          }||d         }|*t          |dd          }|| u s|| u r
t          |= d}N	 ddd           n# 1 swxY w Y   |S )u@  Drop the cache entry whose stored client is *target*.

    Used when a specific cached client has been poisoned (closed httpx
    transport after a timeout, broken streaming session, etc.) so the next
    auxiliary call rebuilds rather than reusing the dead instance.

    Walks both sync and async wrappers (``CodexAuxiliaryClient``,
    ``AnthropicAuxiliaryClient``, ``AsyncCodexAuxiliaryClient``, etc.) via
    their ``_real_client`` attribute so a timeout that closes the underlying
    ``OpenAI`` (or native provider) client evicts every cached shim that
    exposed it. Async wrappers must mirror their sync sibling's
    ``_real_client`` for this to work — otherwise the sync entry is evicted
    but the async entry survives and keeps reusing the dead transport.

    Returns True when at least one entry was evicted.
    NFr   r  T)r,  ra  r-  keysrp   r   )r1  evictedr   r   cachedreals         r   r-  r-  <
  s    " ~uG	  **,,-- 
	 
	C!%%c**E}1XF~6>488D46>>!#&
	               Ns   A5BBBr  c                V   t          |           }|dk    r?t          |          }t          |                    d          pt                                }|dv rdS t	          |          }|dS t          t          |dd          pd                                          }|sdS | d| S )z9Return a stable cache discriminator for pooled providers.rb   r`   >   r:   rb   rf   r:   NrK  rd   )rt   r  rp   rn   r   r   r   rj   )r`   r  rq   rZ  r   entry_ids         r   _pool_cache_hintr:  _
  s     )22JV),77,W[[-D-D-]H[H]H]^^
+++rZ((E}r75$++1r2288::H r%%8%%%r   c                 X    t          | dd           }dt          |           i}|||d<   |S )Nr  rE  )r   r   )r   r  r+  s      r   _pool_error_contextr<  t
  s8    S-..F(#c((3G!'Nr   resolved_providerr  c                    t          |           }|dvr|S t          t          |dd          pd          }t          |d          rdS t          |d          rdS t          |d          rd	S t          |d
          rdS t          |d          rdS t          |d          rdS t          |d          rdS |rt	          |          }|                    dd          }|r|dvr	 ddlm} |                    |          }|rit          |dd          dk    rTt          t          |dd          pd                              d          }	|	rt          |t          |	                    r|S n# t          $ r Y nw xY wdS )zCInfer which provider pool can recover the current auxiliary client.>   r:   rb   rf   r   r:   zchatgpt.comrh   rw  r   inference-api.nousresearch.comr  r  rV   r6  rW   r   rP   zapi.x.air!  r`   r   )r.  r8  Nr  r   rx   )rt   r   r   r0   r  rp   r
  r.  r   r1   r   )
r=  r  r  rq   basertrt_providerr.  r<  rt_bases
             r   _recoverable_pool_providerrD  |
  s    )):;;J///wvz2..4"55DT=11 ~T?33 |T#CDD vT#677 {T#:;; yT>22 }T:.. {  $\22ffZ,, 		;.DDD======+//<< +wwTBBiOO!''3G"L"L"RPRSSZZ[^__G +#8?PQX?Y?Y#Z#Z +**   4s   "BE) )
E65E6failed_api_keyrF  c                   t          |           }	 t          |          }n4# t          $ r'}t                              d||           Y d}~dS d}~ww xY w|r|                                sdS t          |dd          }t          |          }|pd}t          |          rX|	                                }	|	t          |           dS |                    ||nd||          }
|
t          |           dS dS t          |          st          |          rBt          |          rdnd	}|                    ||n|||          }
|
t          |           dS dS )
av  Try same-provider credential-pool recovery for auxiliary calls.

    ``failed_api_key`` is the API key that was actually used for the failing
    request.  Passing it lets mark_exhausted_and_rotate identify the correct
    pool entry even when another process has already rotated the pool (which
    would leave current() as None, causing the wrong entry to be marked).
    z9Auxiliary client: could not load pool for %s recovery: %sNFr  Tr  )r  error_contextapi_key_hintr  r  )rt   r-   r   r   r   r   r   r<  r  try_refresh_currentr0  mark_exhausted_and_rotater  r  )r`   r   rF  rq   r   load_excr  rH  hint	refreshed
next_entryfallback_statuss               r   _recover_provider_poolrQ  
  s    )22J$$   PR\^fggguuuuu  t++-- u#}d33K',,M!TDc ,,..	 !*---433'2'>C' 4 
 


 !!*---4u 	!5c!:!: 	!23!7!7@##S33'2'>O' 4 
 


 !!*---45s   ! 
AAAresolved_modelresolved_base_urlresolved_api_keyresolved_api_moder  r
  r  r  r  effective_timeouteffective_extra_bodyc                    | dk    rt          ||||d          \  }}}nt          ||||||          \  }}|t          d| pd d| d          t          t	          |d	d
          pd
          }t          ||p|||	|
||||p|	  	        }t          ||          rt          |d                   |d<   t           |j	        j
        j        di ||           S )NrQ  Fr`   rv   r   r  
async_moder   r  r  r  
Auxiliary r  : provider $ could not be rebuilt after recoveryr   r:   r  r  r  r  r  r   r
  r   resolve_vision_provider_client_get_cached_clientrk  r   r   _build_call_kwargs_is_anthropic_compat_endpoint#_convert_openai_images_to_anthropic_validate_llm_responser  r  rj  )r  r=  rR  rS  rT  rU  r  r  r
  r  r  r  rV  rW  rt  retry_clientretry_model
retry_baseretry_kwargss                      r   _retry_same_provider_syncrk  
  sU   " x'E&&$(
 (
 (
$< %7&$&%%
 %
 %
!k kkk4Ekkk
 
 	
 W\:r::@bAAJ%"{!'00
 
 
L %%6
CC a#F|T^G_#`#`Z !,%,<<|<<d  r   c                   K   | dk    rt          ||||d          \  }}}nt          ||d|||          \  }}|t          d| pd d| d          t          t	          |d	d
          pd
          }t          ||p||||	|
|||p|	  	        }t          ||          rt          |d                   |d<   t           |j	        j
        j        di | d {V |           S )NrQ  TrY  rZ  r   r  r  r\  r  r]  r^  r   r:   r_  r
  r   r`  )r  r=  rR  rS  rT  rU  r  r
  r  r  r  rV  rW  rt  rg  rh  ri  rj  s                     r   _retry_same_provider_asyncrn    sk       x'E&&$(
 (
 (
$< %7&$&%
 %
 %
!k kkk4Ekkk
 
 	
 W\:r::@bAAJ%"{!'00
 
 
L %%6
CC a#F|T^G_#`#`Z !2l+2BB\BBBBBBBBD  r   c                    t          |           }	 |dk    r\ddlm}  |d          }t          |                    dd          pd                                          sdS t          |           dS |d	k    r}dd
lm}  |t          t          j
        dd                    d          }t          |                    dd          pd                                          sdS t          |           dS |dk    rddlm}m}m}  |            }t          |t                     r |                    d          r ||          nd}t          |pd                                          s
 |            }t          |pd                                          sdS t          |           dS |dk    rt#          |          }	|	r|	                                rm|	                                 |	                                }
|
Ct          t+          |
dd          pd                                          rt          |           dS ddlm}  |d          }t          |                    dd          pd                                          sdS t          |           dS n4# t.          $ r'}t0                              d||           Y d}~dS d}~ww xY wdS )zERefresh short-lived credentials for OAuth-backed auxiliary providers.rh   r   )!resolve_codex_runtime_credentialsTr  r  r:   Fr  r  r  r  r  rV   )read_claude_code_credentials_refresh_oauth_tokenr  refreshTokenNr!  r   r$  z7Auxiliary provider credential refresh failed for %s: %s)rt   r
  rp  r   rp   rj   r0  r  r   r   r  r  rq  rr  r  r"   r   r-   r   r   rJ  r   r%  r   r   r   )r`   rq   rp  r  r  rq  rr  r  r  r   rN  r%  r   s                r   _refresh_provider_credentialsrt  K  sP   (22J3''IIIIII55DIIIEuyyB//5266<<>> u!*---4HHHHHH44 %bi0Mt&T&T U U"  E uyyB//5266<<>> u!*---4$${{{{{{{{{{0022E3=eT3J3JruyyYgOhOhr((///nrEu{##))++ 2//11u{##))++ u!*---4$$ Z((D  ,,..   4466	(SDUWY1Z1Z1`^`-a-a-g-g-i-i()*5554MMMMMM99MMMEuyyB//5266<<>> u!*---4# %$    NPZ\_```uuuuu 5sL   AJ "J 3A0J %J 6B!J J *BJ A	J J 
K)KKpayment errorfailed_providerreasonc           	         |                                                                  }t                      }|h}|r=|                                 |v r'|                    |                                            dddddddfd|D             }g }t	                      D ]\  }}	||v r
t          |          r)t          ||           |                    | d           B |	            \  }
}|
*t          	                    d	|pd
|| ||pd           |
||fc S |                    |           t          
                    d|pd
|| d                    |                     dS )zTry alternative providers after a payment/credit or connection error.

    Iterates the standard auto-detection chain, skipping the provider that
    failed.

    Returns:
        (client, model, provider_label) or (None, None, "") if no fallback.
    r   r  rh   r  )r   r  rh   rg   rf   r  c                 <    h | ]}                     ||          S r   rp   )r>   s_alias_to_labels     r   	<setcomp>z(_try_payment_fallback.<locals>.<setcomp>  s)    HHHq,,Q22HHHr    (unhealthy)Nu2   Auxiliary %s: %s on %s — falling back to %s (%s)r  r@  z<Auxiliary %s: %s on %s and no fallback available (tried: %s), NNr:   )rk   rj   rn   addr  r9  r  r]  r   r  rb  rm  )rv  r  rw  skipmain_providerskip_labelsskip_chain_labelstriedr  try_fnr  rv   r|  s               @r   _try_payment_fallbackr    s      ""((**D ())M&K /,,..$66++--...%16'5!/Q QO IHHHKHHHE,..  v%%%!%(( 	t,,,LLE///000KKD@R   5%''''U
NNF51A1A   >r   errorc                 F   t                      pd                                }t                      pd                                }|r|r|                                dv rdS | pd                                                                }|                                |k    rdS t	          |          rt          ||           dS 	 t          ||          \  }}n# t          $ r d\  }}Y nw xY w|dS d| d}t          	                    d	|pd
|| ||p|           ||p||fS )a  Last-resort fallback to the user's main agent provider + model.

    Used after the configured fallback_chain is exhausted (or empty) for
    users with an explicit auxiliary provider.  This is the "safety net"
    layer: if nothing the user asked for can serve the request, try the
    main chat model before giving up.

    Skips when the failed provider already IS the main provider (no point
    retrying the same backend that just failed).

    Returns:
        (client, model, provider_label) or (None, None, "") if no fallback.
    r:   >   r:   rb   r  r`   rv   r0  Nzmain-agent()uC   Auxiliary %s: %s on %s — falling back to main agent model %s (%s)r  )
rn   rj   rg  rk   r9  r  resolve_provider_clientr   r   r  )	rv  r  rw  r  
main_modelr  r  rR  r  s	            r   _try_main_agent_model_fallbackr    sv   $ )**0b7799M"$$*1133J 
 m.A.A.C.C|.S.S~!r((**0022D$$~m,, M4000~,!8"*"
 "
 "
  , , ,!+, ~~*-***E
KKM8T*   >/Z66s   C C,+C,c           	      Z   | sdS t          |           }|                    d          }|rt          |t                    sdS |                                                                }g }t          |          D ]\  }}t          |t                    st          |                    dd                                                    }	|	r|	                                |k    rlt          |                    dd                                                    pd}
t          |                    dd                                                    pd}t          |                    dd                                                    pd}d	| d
|	 d}	 t          |	|
||          }n# t          $ r d}Y nw xY w|(t                              d| ||||
pd           ||
|fc S |                    |           |r/t                              d| d                    |                     dS )ag  Try user-configured fallback_chain for a specific auxiliary task.

    Reads auxiliary.<task>.fallback_chain from config.yaml and tries each
    entry in order.  Each entry must have at least ``provider``; ``model``,
    ``base_url``, and ``api_key`` are optional.

    Returns:
        (client, model, provider_label) or (None, None, "") if no fallback.
    r  fallback_chainr`   r:   rv   Nr   r  zfallback_chain[z](r  u9   Auxiliary %s: %s on %s — configured fallback to %s (%s)r@  z=Auxiliary %s: configured fallback_chain exhausted (tried: %s)r  )_get_auxiliary_task_configrp   r"   ra  rk   rj   	enumerater   r   _resolve_single_providerr   r   r  r]  r   rm  )r  rv  rw  task_configchainr  r  ir   fb_providerfb_modelfb_base_url
fb_api_keyr  	fb_clients                  r   _try_configured_fallback_chainr    s]     ~,T22KOO,--E 
5$// ~  ""((**DEe$$  5%&& 	%))J3344::<< 	k//11T99uyy"--..4466>$%))J3344::<<D9b112288::Bd
5!55{555	0X{J@ @II 	 	 	III	  KKKfouh6K)   h----U 
K$))E""	
 	
 	
 >s   F''F65F6c                 2    t          | |||          \  }}|S )zResolve a single provider entry from fallback_chain to an OpenAI client.

    Uses the existing provider resolution infrastructure where possible.
    )r`   rv   r   r  )r  )r`   rv   r   r  r  rR  s         r   r  r  $  s0     5	  FN Mr   c           	      h   da t          |           }|                    dd          }t          |                    d          pd          }t          |                    d          pd          }|                    dd          }t          |                    d          pd          }|st          rt          }|st
          rt
          }|st          rt          }t          stt          j	        dd          
                                }|pt                      }|r;|r9|d	k    r3|                    d
          st                              d||           dat          |pt                      pd          }	t          |pt                      pd          }
|	r|
r|	dvr|	}d}d}|r$|	d	k    s|	                    d
          r	d	}|}|pd}n|r|}t!          |          }|rt#          |          rt%          |           n?t'          ||
|||pd          \  }}|$t                              d|	|p|
           ||p|
fS g }t+                      D ]\  }}t#          |          r(t%          |           |                    | d           < |            \  }}|Y|r3t                              d||pdd                    |                     nt                              d||pd           ||fc S |                    |           t                              dd                    |                     dS )u  Full auto-detection chain.

    Priority:
      1. User's main provider + main model, regardless of provider type.
         This means auxiliary tasks (compression, vision, web extraction,
         session search, etc.) use the same model the user configured for
         chat.  Users on OpenRouter/Nous get their chosen chat model; users
         on DeepSeek/ZAI/Alibaba get theirs; etc.  Running aux tasks on the
         user's picked model keeps behavior predictable — no surprise
         switches to a cheap fallback model for side tasks.
      2. OpenRouter → Nous → custom → Codex → API-key providers (fallback
         chain, only used when the main provider has no working client).
    Fr`   r:   rv   r   r  r  rt  rf   rc   zOPENAI_BASE_URL is set (%s) but model.provider is '%s'. Auxiliary clients may route to the wrong endpoint. Run: hermes model to reconfigure, or remove OPENAI_BASE_URL from ~/.hermes/.envT>   r:   rb   N)r  rF  r  z2Auxiliary auto-detect: using main provider %s (%s)r~  u4   Auxiliary auto-detect: using %s (%s) — skipped: %sr@  r  z$Auxiliary auto-detect: using %s (%s)zAuxiliary auto-detect: no provider available (tried: %s). Compression, summarization, and memory flush will not work. Set OPENROUTER_API_KEY or configure a local model in config.yaml.r0  )r   r  rp   r   rj  rk  rl  _stale_base_url_warnedr   r  rj   rn   rl   r   rb  rg  r  r9  r  r  r  r  r]  rm  )r  rZ  runtime_providerruntime_modelr   r   r  	_env_base_cfg_providerr  r  r=  r  rF  main_chain_labelr  r  r  r  r  rv   s                        r   _resolve_autor  7  s    %l33G{{:r22G,,233M7;;z228b99kk)R00O7;;z228b99  2 6 21 04 0/ 2 6 21 " *I/44::<<	(A,?,A,A 
	*- 
	*!X--%00;; .NN6 =   &*" (G,?,A,AGRHHM]>&6&8&8>B??J !6* !6\11)  	/(!:!:m>V>VW`>a>a!: ( 0.6$ 	/  / 22CDD 	6 67G H H 	6 011116!"3!1)1T     FH !P)8+AzC C Cx5:55 E,..  v!%(( 	&&&LLE///000 _R!5#5Ityy7G7GI I I I BE5K]T]^^^5=   U
NN W 99U##% % % :r   	is_visionc                    ddl m} t          | t                    rt	          |           |fS t          | t
                    rt          |           |fS 	 ddlm}m	} t          | |          r ||           |fS n# t          $ r Y nw xY w	 ddlm} t          | |          r| |fS n# t          $ r Y nw xY w| j        t          | j                  d}t          | j                  }t!          |d          rt#                      |d<   nt!          |d          rdd	lm}	  |	d
|          |d<   nt!          |d          rddi|d<   nyt!          |d          rt)          |          |d<   nV	 ddlm}
 ddlm}  |
|          }|r+ ||          }|r|j        rt5          |j                  |d<   n# t6          $ r Y nw xY wt9          |                    d                    }|r||d<    |di ||fS )aa  Convert a sync client to its async counterpart, preserving Codex routing.

    When ``is_vision=True`` and the underlying base URL is Copilot, the
    resulting async client carries the ``Copilot-Vision-Request: true``
    header so the request is routed to Copilot's vision-capable
    infrastructure (otherwise vision payloads silently time out).
    r   )AsyncOpenAI)r  AsyncGeminiNativeClientr  r4  rw  r   r6  copilot_request_headersTis_agent_turnr  r   r   r5  r   )_infer_provider_from_urlr   r   )r   r  r"   r  r  r  r  r  r  r  r  r  r  r  r   r   r0   r   hermes_cli.copilot_authr  r   agent.model_metadatar  r   r   r   r   r   r   rp   )sync_clientrv   r  r  r  r  r  async_kwargssync_base_urlr  r  
_gpf_async	_inferred	_ph_async_merged_asyncs                  r   _to_async_clientr    s    #"""""+344 =(55u<<+788 A,[995@@[[[[[[[[k#566 	?**;77>>	?   ======k#344 	&%%	&    &,-- L ,--M]O<< *:*<*<&''	}.E	F	F CCCCCC*A*A)+
 +
 +
&'' 
}n	=	= +79L*M&''	}.H	I	I *B=*Q*Q&''
		EEEEEEDDDDDD00??I V&Jy11	 V!: V6:9;T6U6UL!23 	 	 	D	/0@0@AR0S0STTM 8*7&';&&&&--s7   $A: :
BBB& &
B32B3+AF0 0
F=<F=
model_namec                 T    | s| S 	 ddl m}  || |          S # t          $ r | cY S w xY w)zANormalize a resolved model for the provider that will receive it.r   )normalize_model_for_provider)hermes_cli.model_normalizer  r   )r  r`   r  s      r   r  r    sa     KKKKKK++JAAA   s    ''rZ  	raw_codexc	                 (#  J t                       | pd                                                                }	t          |           } |st	          |           pt                      p|}dt          dt          dt          ffdJ	 	 djdt          dt          dt          fJfd}
| d	k    r]t          |
          \  }}|dS |r(d|v r$|r"d|vrt          
                    d||           d}|p|}|rt          |||          n||fS | dk    rht          |          \  }}|)t                              dt                                 dS t          |p||           }|rt          |||          n||fS | dk    r|t                                           v p+|pd                                                                dk    }t%          |          \  }}|t                              d           dS t          |p||           }|rt          |||          n||fS | dk    r|st                              d           dS rdt'                      }|st                              d           dS t          ||           }t)          |t*          t-          |                    }||fS t/          |          \  }}|t                              d           dS t          |p||           }|rt          |||          n||fS | dk    rZt1          |          \  }}|t                              d           dS t          |p||           }|rt          |||          n||fS | dk    r|rt3          |                                          }|pd                                p(t5          j        dd                                          pd}|st                              d            dS t          |p|r|                    d!          ndpd"|           }i }t;          |          \  }}|r||d#<   t=          |d$          rd%d&i|d'<   nt=          |d(          rd)d*lm }  |d+|,          |d'<   nft=          |d-          rtC          |          |d'<   nC	 d)d.l"m#}  ||           }|r|j$        rtK          |j$                  |d'<   n# tL          $ r Y nw xY wtO          |                    d'                    }|r||d'<   t)          dk||d/|} |
||||          }|rt          |||          n||fS tP          tR          fD ]} |            \  }}|t          |p||           }t          tU          |d0d          pd          }tU          |d1d          }tW          |          rtY          |t                    sdnt          |pd          } |
||||          }|rt          |||          n||fc S t                              d2           dS 	 d)d3l-m.} d} |	r|	| k    r ||	          } |  ||           } | rT|                     d0d                                          }|                     d1d                                          }|                     d4          p|                     d5          pd                                }!|s)|!r't5          j        |!d                                          }|pd}|dk    r0t                              d6|                     d7          p|            p|                     d8          pd                                }"|rt          |p=|                     d!          p(|r|                    d!          ndpt                      pd"|           }|"d9k    r|}#|}$nt3          |          }#|}$t;          |#          \  }%}&|&rd#|&ini }'tO          |'                    d'                    }(|(r|(|'d'<   t          
                    d:| ||"pd;           |"d9k    r	 d)d<l/m0})  |)||          }*n# tb          $ r t                              d=|            t3          |          }+t;          |+          \  },}-|-rd#|-ini }.tO          |.                    d'                    }/|/r|/|.d'<   t)          dk||,d/|.}|rt          |||          n||fcY S w xY wte          |*|||d>?          }0|rtg          |0          |fS |0|fS t)          dk||%d/|'}|"d@k    r&tY          |th                    sti          ||          }n |
|||$|          }|rt          |||          n||fS t                              dA|            dS n# tb          $ r Y nw xY w| dBk    r^tk          |||C          \  }}1|t                              dD           dS t          |p|1|           }|rt          |||          n||fS 	 d)dEl6m7}2m8}3m9}4 n,# tb          $ r t          
                    dF|            Y dS w xY w|2                    |           }5|5t                              dG|            dS |5j:        d1k    r| dHk    r[tw          |          \  }}1|t                              dI           dS t          |p|1|           }|rt          |||          n||fS  |3|           }6t          |6                    d1d                                                    }7|r|                                p|7}7|7s`ty          |5j=                  }8| dJk    r|8>                    dK           t          
                    dL| dM?                    |8                     dS t          |6                    d0d                                                    @                    d          p|5jA        }9t3          |9          }:|r4t3          |                                @                    d                    }:t	          |           }1t          |p|1|           }| dNk    rTd)dOlBmC};mD}<  |<|:          rA |;|7|:/          }t          
                    dP| |           |rt          |||          n||fS i }=t=          |:d$          rd&|=d%<   nt=          |:d(          r'd)d*lm } |=E                     |d+|,                     nyt=          |:d-          r#|=E                    tC          |:                     nF	 d)d.l"m#}>  |>|           }?|?r!|?j$        r|=E                    |?j$                   n# tL          $ r Y nw xY wtO          |=          }@|@r|@}=t)          dk|7|:d/|=rd'|=ini }| dJk    rR|rPsN	 d)dQlFmG}A  |A|          r+t          
                    dR|           ti          ||          }n# tb          $ r Y nw xY w |
|||9|7          }t          
                    dP| |           |rt          |||          n||fS |5j:        dSk    r |4|           }6t          |p&|r|                    d!          ndpt                      |           }| dTk    rLt          |6                    d1d                                                    }7t          |6                    d0d                                                    }:t          |6                    dUd                                                    pd}Bty          |6                    dV          pg           }C|st                              dW           dS |7r|:st                              dX           dS d)dYlHmI}D  |D|7|:|B|CZ          }t          
                    dP| |           |rt          |||          n||fS t                              d[|            dS |5j:        d\k    r
	 d)d]lJmK}EmL}F d)d^l/mM}G n+# tb          $ r t                              d_           Y dS w xY w |E            st          
                    d`           dS  |F            }Hda}1t          |p|1|           }	  |G|H          }*n3# tb          $ r&}It                              db|I           Y d}I~IdS d}I~Iww xY wte          |*|dcdd|H de/          }t          
                    df||H           |rt          |||          n||fS |5j:        dgv rb| dk    rt          d||          S | dk    rt          d||          S | dk    rt          d||          S t                              dh|            dS t                              di|5j:        |            dS )lu  Central router: given a provider name and optional model, return a
    configured client with the correct auth, base URL, and API format.

    The returned client always exposes ``.chat.completions.create()`` — for
    Codex/Responses API providers, an adapter handles the translation
    transparently.

    Args:
        provider: Provider identifier.  One of:
            "openrouter", "nous", "openai-codex" (or "codex"),
            "zai", "kimi-coding", "minimax", "minimax-cn",
            "custom" (OPENAI_BASE_URL + OPENAI_API_KEY),
            "auto" (full auto-detection chain).
        model: Model slug override.  If None, uses the provider's default
               auxiliary model.
        async_mode: If True, return an async-compatible client.
        raw_codex: If True, return a raw OpenAI client for Codex providers
            instead of wrapping in CodexAuxiliaryClient.  Use this when
            the caller needs direct access to responses.stream() (e.g.,
            the main agent loop).
        explicit_base_url: Optional direct OpenAI-compatible endpoint.
        explicit_api_key: Optional API key paired with explicit_base_url.
        api_mode: API mode override.  One of "chat_completions",
            "codex_responses", or None (auto-detect).  When set to
            "codex_responses", the client is wrapped in
            CodexAuxiliaryClient to route through the Responses API.

    Returns:
        (client, resolved_model) or (None, None) if auth is unavailable.
    r:   base_url_str	model_strr   c                     t          | t                    rdS rdS dk    rdS rdk    rdS t          |          dk    r|pd                                }d|v rdS dS )a(  Decide if a plain OpenAI client should be wrapped for Responses API.

        Returns True when api_mode is explicitly "codex_responses", or when
        auto-detection (api.openai.com + codex-family model) suggests it.
        Already-wrapped clients (CodexAuxiliaryClient) are skipped.
        Fr  Tapi.openai.comr:   rg   )r"   r  r1   rk   )r  r  r  model_lowerr  r  s       r   _needs_codex_wrapz2resolve_provider_client.<locals>._needs_codex_wrapW  s     j"677 	5 	5(((4 	$5555\**.>>>$?1133K+%%tur   final_model_strapi_key_strc                      | ||          r;t                               dpd||r
|dd         nd           t          | |          S t          | |||          S )a@  Wrap a plain OpenAI client in the correct transport adapter.

        Handles two cases:
        - ``CodexAuxiliaryClient`` when the endpoint needs the Responses API
          (explicit ``api_mode=codex_responses`` or api.openai.com + codex
          model name).
        - ``AnthropicAuxiliaryClient`` when the endpoint speaks Anthropic
          Messages (explicit ``api_mode=anthropic_messages``, any ``/anthropic``
          suffix, ``api.kimi.com/coding``, or ``api.anthropic.com``).

        Clients that are already specialized wrappers pass through unchanged.
        zeresolve_provider_client: wrapping client in CodexAuxiliaryClient (api_mode=%s, model=%s, base_url=%s)r  Nr  r:   )r   r   r  r  )r  r  r  r  r  r  s       r   _wrap_if_neededz0resolve_provider_client.<locals>._wrap_if_neededm  s     ZGG 	ELL7+O_%19SbS!!r	; ; ;
 (
ODDD %lH
 
 	
r   rb   r7  Nr0  rx   z\Dropping OpenRouter-format model %r for non-OpenRouter auxiliary provider (using %r instead)r  r   )rF  z4resolve_provider_client: openrouter requested but %sr  zmimo-v2-omnirV  zYresolve_provider_client: nous requested but Nous Portal not configured (run: hermes auth)rh   zresolve_provider_client: openai-codex requested without a model; pass model explicitly (e.g. model.model in config.yaml or auxiliary.<task>.model for per-task aux routing).zbresolve_provider_client: openai-codex requested but no Codex OAuth token found (run: hermes model)rI  r!  u   resolve_provider_client: xai-oauth requested but no xAI OAuth token found (run: hermes model -> xAI Grok OAuth — SuperGrok / Premium+)rf   ru  rx  zQresolve_provider_client: explicit custom endpoint requested but base_url is emptyrv   r  r  r   r   r5  r   r6  r   r  Tr  r   r   r4  r   r  zPresolve_provider_client: custom/main requested but no endpoint credentials found)_get_named_custom_providerkey_envapi_key_envu   resolve_provider_client: named custom provider %r has no resolvable api_key — request will be sent with placeholder no-key-required and will 401 on auth-required endpointsr!  r  r  zCresolve_provider_client: named custom provider %r (%s, api_mode=%s)r  r  u   Named custom provider %r declares api_mode=anthropic_messages but the anthropic SDK is not installed — falling back to OpenAI-wire.Fr  r  zAresolve_provider_client: named custom provider %r has no base_urlr  r  zsresolve_provider_client: azure-foundry requested but runtime resolution failed (run: hermes doctor for diagnostics))r.  r/  -resolve_external_process_provider_credentialsz-hermes_cli.auth not available for provider %sz,resolve_provider_client: unknown provider %rrV   zOresolve_provider_client: anthropic requested but no Anthropic credentials foundrW   zgh auth tokenzJresolve_provider_client: provider %s has no API key configured (tried: %s)r  rI   r2  z resolve_provider_client: %s (%s))!_should_use_copilot_responses_apiud   resolve_provider_client: copilot model %s needs Responses API — wrapping with CodexAuxiliaryClientexternal_processrX   commandr   zVresolve_provider_client: copilot-acp requested but no model was provided or configuredz^resolve_provider_client: copilot-acp requested but external process credentials are incompleter  )r  r   r  r   zLresolve_provider_client: external-process provider %s not directly supportedaws_sdk)has_aws_credentialsresolve_bedrock_region)build_anthropic_bedrock_clientzSresolve_provider_client: bedrock requested but boto3 or anthropic SDK not installedzGresolve_provider_client: bedrock requested but no AWS credentials foundz(anthropic.claude-haiku-4-5-20251001-v1:0z9resolve_provider_client: cannot create Bedrock client: %szaws-sdkzhttps://bedrock-runtime.z.amazonaws.comz)resolve_provider_client: bedrock (%s, %s)>   oauth_externaloauth_device_codezMresolve_provider_client: OAuth provider %s not directly supported, try 'auto'z6resolve_provider_client: unhandled auth_type %s for %s)r:   r:   r   )Or  rj   rk   rt   r   rg  r   r  r  r   r   r  rN  rb  rP  r  r   valuesr\  r,  r   r  r   r  r  r   r   r  rp   rG   r0   r  r  r   r   r   r   r   r   r   r  rE  r   r   r"   ry  r  r  r  r  r  r  r  r  r
  r.  r/  r  r8  r:  ra  api_key_env_varsr]  rm  r   r   r  r  r3  updater;  r  r  r  agent.bedrock_adapterr  r  r  r  )Kr`   rv   rZ  r  r  rF  r  r  r  original_providerr  r  r  r  r@  
_is_visionr  
raw_clientr|  r}  r>  r  r  r  _gpf_custom
_ph_custom_merged_customr  _cbase	_raw_ckey_ckeyr  custom_entrycustom_key_enventry_api_moderz  raw_base_for_wrap_clean_base2_dq2_extra2	_headers2r  r  _fallback_base	_fb_clean_fb_dq	_fb_extra_fb_headerssync_anthropicdefault_modelr.  r/  r  r<  r  r  tried_sourcesr=  r   r  r3  r   	_gpf_main_ph_main_merged_mainr  r  r   r  r  r  r  regionr   r  sK      `  `                                                                   @r   r  r    s   R  "R..006688&x00H6  U+H55T9I9K9KTuC C D       , OQ+-
 
S 
 
%(
 
 
 
 
 
 
8 6(lCCC>:
  	SE\\h\3h3F3FLL89>J J J E'xNX + 	JJJJk*	, <);KLLL>NNF022   :/0@(KKNX + 	JJJJk*	, 6 ,33555 ?""$$**,,> 	 $:666>NN O P P P:/0@(KKNX + 	JJJJk*	, >!! 	NNG  
 : 	- 344K "  T U U U!z3E8DDK#, 9+ F F  J
 ,,-e44>NN P Q Q Q:/0@(KKNX + 	JJJJk*	, ;5e<<>NNc   :/0@(KKNX + 	JJJJk*	, 8 .	0-.?@@FFHHK!'R..00 %9-r2288::%$ 
  ",   "z3_|M,**7333_R_ K E8EEK -),o&$[.AA ,8:M+N'((&{4KLL KKKKKK+B+B"&), , ,'(( '{4NOO +CK+P+P'((MMMMMM!,X!6!6J! Tj&@ T37
8R3S3S/0    D8CT9U9UVVN :+9'(NJNNNNF$_V[+zRRFR\ /$V[INNNN +.0 ,-FG 	4 	4F$fhhOFG!78H(SSWVZ<<BCC $FIr::	'	22p:iQT;U;Up\_`i`omo\p\p(feLLV` 3(	RRRR$k24 4 4 " 	 ; 	< 	< 	<zkJJJJJJ  	I!2h!>!>556GHHL55h??L [	&**:r::@@BBK%)))R88>>@@J*..y99b\=M=Mm=\=\b`biikkN C. CY~r::@@BB
#8'8J...> !$$V,,8	   'L,*:*::*F*FL"SSUUN F47 %#''00%5AK((111t% ())% %  "%999"-K(3%%"5k"B"BK(3%%>{%K%K"d59A?D11r7DU8V8VWW	 ;1:G-.Yk>+O=OQ Q Q "%999<RRRRRR&<&<Z&U&U& < < <I %	   *=[)I)I,En,U,U)	6AG$O_f$=$=R	&A)--PaBbBb&c&c& G;FI&78!'!\
Y!\!\R[!\!\^h !; 0PY Z Z Z Z&,k%:< < <!<$ &>#[*kTY& & &N " Z<^LLkYY);66U
\UUWUU
 "%666z0@ @6 2&+FFFF,_V[BSU_``FV` 3(	RRRR$k24NNS   :w[	x    & ?"" 2-/	!
 !
 !
 >NN  
 :/0FQQNX + 	JJJJk*	,	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	

    DhOOOzz  ##H--GExPPPzI%%{""$2DT$U$U$U!FM~pqqq!z3E4J]HUUKR\w$V[INNNNcikvbwx44X>>eii	2..//5577
  	:&,,..9'G 	 !9::M9$$$$_555LL 6!499]#;#;= = = :599Z4455;;==DDSIIgWMg&|44  	R*+<+B+B+D+D+K+KC+P+PQQH3H==/0FQQxaaaaaaaa((22 4++GhOOO?;WWWV` 3(	RRRR$k24  >:: 	$7GL!!"8-DEE 	GGGGGGNN22"i       #8-GHH 	NN3H==>>>>
GGGGGG$9X.. = 8 =NN8#;<<<   27;; 	#"G M( M M;BJ-w77M M y  [  	OOOOOO44[AA GLLO#% % % 2&+FFF    !lGLL7;OOONX + 	JJJJk*	, ...==hGG/ "-9C  )))t"!!	
 
 }$$%))Ir223399;;G599Z4455;;==H%))Ir223399;;CtG		&))/R00D "1   "z "( "9   "zAAAAAA%%!	  F LL;X{SSSR\ /$V[INNNN +.0 ,-5	7 	7 	7z		i	'	'	YYYYYYYYNNNNNNN 	 	 	NN B C C C::	
 #"$$ 	LL 4 5 5 5:''))B/0FQQ	88@@KK 	 	 	NN (),. . .:::::	 *iFFFF
 
 
 	@+vVVVNX + 	JJJJk*	, 
	E	E	Ev*65*EEE~%%*>5*MMM{""*;zJJJ 89A	C 	C 	Cz
NNK$h0 0 0:s   1S 
SSHf 1a f Bc%"f $c%%)f f A f 4f 
ff
h %h;:h;+4u   
u-,u-#<w   
w-,w-=A@ @$A@4@3A@4A<AB B
AB8BAB3B3AB8c                Z    t          | pd          \  }}}}}t          ||||||          S )aR  Return (client, default_model_slug) for text-only auxiliary tasks.

    Args:
        task: Optional task name ("compression", "web_extract") to check
              for a task-specific provider override.

    Callers may override the returned model via config.yaml
    (e.g. auxiliary.compression.model, auxiliary.web_extract.model).
    N)rv   r  rF  r  r  _resolve_task_provider_modelr  r  r  r`   rv   r   r  r  s          r   get_text_auxiliary_clientr    sM     4PPTP\X\3]3]0HeXw"" !   r   c          	      \    t          | pd          \  }}}}}t          ||d||||          S )a  Return (async_client, model_slug) for async consumers.

    For standard providers returns (AsyncOpenAI, model). For Codex returns
    (AsyncCodexAuxiliaryClient, model) which wraps the Responses API.
    Returns (None, None) when no provider is available.
    NT)rv   rZ  r  rF  r  r  r  r  s          r   get_async_text_auxiliary_clientr    sP     4PPTP\X\3]3]0HeXw"" !   r   )r   r  c                     	 ddl m} ddlm} n# t          $ r Y dS w xY w	  || | |                      }n# t
          $ r Y dS w xY w|dS t          |          S )u  Return True when ``provider``/``model`` is known to accept image input.

    Used by the vision auto-detect chain to skip the user's main provider
    when it's known to be text-only (e.g. DeepSeek, gpt-oss without vision).
    Without this guard, ``resolve_vision_provider_client(provider="auto")``
    would happily return the main-provider client and any subsequent image
    payload would surface as a cryptic provider-side error
    (``unknown variant `image_url`, expected `text```, #31179).

    Returns True when capability lookup is unknown — preserves the historical
    behaviour of attempting the call, so providers we haven't catalogued yet
    don't silently regress to text-only.
    r   )_lookup_supports_visionr   T)agent.image_routingr  r   r   r  r   r  )r`   rv   r  r   supportss        r   _main_model_supports_visionr    s    ??????1111111   tt**8UKKMMJJ   tt t>>s    
7 
AAc                      t          |           S r   )rt   r`   s    r   _normalize_vision_providerr    s    "8,,,r   c                 ,   t          |           } | dk    rt          d|d          S | dk    rt          |          S | dk    rt          d          S | dk    rt          d|d          S | d	k    rt	                      S | d
k    rt                      S dS )NrW   Tr  r   rv   r  rV  rh   rV   rf   r0  )r  r  rN  r\  r:  r  r  s     r   _resolve_strict_vision_backendr
    s     *(33H9&y%4HHHH<U++++6%%%%>!! '~uMMMM;8#%%%:r   c                 0    t          |           d         d uS r  )r
  r  s    r    _strict_vision_backend_availabler    s    )(33A6dBBr   c                  ^   g } t                      }|rh|dvrd|t          v r%t          |          r|                     |           n6t	          |t                                \  }}||                     |           t          D ]*}|| vr$t          |          r|                     |           +| S )u   Return the currently available vision backends in auto-selection order.

    Order: active provider → OpenRouter → Nous → stop.  This is the single
    source of truth for setup, tool gating, and runtime auto-routing of
    vision tasks.
    >   r:   rb   )rn   _VISION_AUTO_PROVIDER_ORDERr  r]  r  rg  )	availabler  r  rt  r  s        r   get_available_vision_backendsr    s     I'))M 0l::777/>> 0  ////?O?Q?QRRIFA!  ///(    I"B1"E"EQr   )r   r  rZ  c          
      B   t          d| |||          \  }}}}t          |          }dt          dt          dt          t                   ffd}	|r.|r|dvr|nd}
t          |
|||          \  }}||
d	d	fS |
||fS |d
k    rlt                      }t                      }|r|dvrt          	                    ||          }|dk    rCt          ||          \  }}|-t                              d||pp|            |	|||          S n|t          v rt                              d|           nqt          ||          st                              d|           nEt          |||d          \  }}|-t                              d||p|            |	|||p|          S t           D ],}||k    r	t          |          \  }}| |	|||          c S -t                              d           dS |t           v r t          |          \  }} |	|||          S |dk    rZ|sXddg}|D ].}t#          |||pd	dd          \  }}| |	|||          c S /t#          ||d          \  }}||d	d	fS |||fS t#          ||d          \  }}||d	d	fS |||fS )ar  Resolve the client actually used for vision tasks.

    Direct endpoint overrides take precedence over provider selection. Explicit
    provider overrides still use the generic provider router for non-standard
    backends, so users can intentionally force experimental providers. Auto mode
    stays conservative and only tries vision backends known to work today.
    rQ  r=  r  r  c                 \    || d d fS p|}rt          ||d          \  }}| ||fS | ||fS )NTr  )r  )r=  r  r  r  async_clientasync_modelrZ  rR  s         r   	_finalizez1resolve_vision_provider_client.<locals>._finalize3  s]    $dD00$5 	@(8k]a(b(b(b%L+$lK?? +{::r   >   r:   rb   rf   )rv   rZ  r  rF  r  Nrb   r  z/Vision auto-detect: using main provider %s (%s)ui   Vision auto-detect: skipping main provider %s (no vision support) — falling through to aggregator chainut   Vision auto-detect: skipping main provider %s (reports no vision capability) — falling through to aggregator chainT)r  r  z'Auxiliary vision client: none availablerv  rM   z$https://open.bigmodel.cn/api/paas/v4zhttps://api.z.ai/api/paas/v4r  )r   r  r  r  )r  r  r   r   r   r  rn   rg  r   rp   r
  r   r  r   r   r  r  rb  )r`   rv   r   r  rZ  rs  rS  rT  rU  r  provider_for_base_overrider  r  r  r  vision_modelr  r  
rpc_client	rpc_modelr  zai_openai_urls_zai_urlrR  s       `                  @r   ra  ra    s\    Yu(E8WY YUI~02BDU +955I;S ;s ;8TW= ; ; ; ; ; ; ;  ?"Ry'D'DII( 	# 6& !/-&
 
 
 >-tT99)6;>>F ,--%''
 5	N],>>266}jQQL&&-K!<. .*] *KKI%}'T'T*   %9]KOOO + ";;; N!   
 1MM N ' "	    )@!<.")$ )$ )$%
I )KKI%y'@L   %9%z93LN N N
 5 	H 	HIM)))G	)R)R&K& yKGGGGG ' 	>???///%C~&
 &
"] yK??? E"32*
 ( 		A 		AH"4>:!(0D+# # #FK ! yFK@@@@@ " 1NJ:K;?A A A >dD((&+--,Y
6G7;= = =FK ~$$$fk))r   c                  0    t           rt                      ni S )zReturn extra_body kwargs for auxiliary API calls.
    
    Includes Nous Portal product tags when the auxiliary client is backed
    by Nous Portal. Returns empty dict otherwise.
    )r   r   r   r   r   get_auxiliary_extra_bodyr    s     "3::r   r	  r   c                    t                      }t          j        d          }|s#t                      t	          |          dv rd| iS t          |          rd| iS d| iS )u  Return the correct max tokens kwarg for the auxiliary client's provider.

    OpenRouter and local models use 'max_tokens'. Direct OpenAI with newer
    models (gpt-4o, gpt-4.1, gpt-5+, o-series) requires 'max_completion_tokens'.
    The Codex adapter translates max_tokens internally, so we use max_tokens
    for it as well. Pass ``model`` so third-party OpenAI-compatible endpoints
    fronting the newer families are also recognised — URL-only detection
    misses the case where a custom base URL serves e.g. ``gpt-5.4``.
    rJ  N>   r  r6  r  r  )r  r   r  r  r1   r2   )r   rv   r|  rM  s       r   auxiliary_max_tokens_paramr    sz     +,,KY+,,F  0!!)!+..2]]]'//)%00 0'//%  r   r-  @   )r   r  r  r  r  c                   	 t          |          	| dk    r t          	fdt          D                       nd}t          | |          }| ||pd|pd|pd|||fS )Nrb   c              3   D   K   | ]}                     |d           V  dS )r:   Nrz  )r>   r  rZ  s     r   r  z$_client_cache_key.<locals>.<genexpr>	  s1      QQ5E2..QQQQQQr   r   r7  r:   )r  tupler  r:  )
r`   rZ  r   r  r  r  r  runtime_key	pool_hintrZ  s
            @r   _client_cache_keyr&    s~     &l33GU]agUgUg%QQQQ<PQQQQQQmoK EEEIj(.b'-RRQ\^girssr   
bound_loop	cache_keyr  r(  c                Z   t           5  t                              |           }|a|d         |urWt          |d                    	 t	          |d         dd           }t          |          r
 |             n# t          $ r Y nw xY w|||ft          | <   d d d            d S # 1 swxY w Y   d S )Nr   r)  )r,  r-  rp   r.  r   r   r   )r)  r  r  r(  	old_entryr~  s         r   _store_cached_clientr,    s    	 
G 
G!%%i00	 Yq\%?%?$Yq\222"9Q<$??H%% HJJJ   $*M:#Fi 
G 
G 
G 
G 
G 
G 
G 
G 
G 
G 
G 
G 
G 
G 
G 
G 
G 
Gs5   <B 0A65B 6
B B BB  B$'B$cache_providerc           	      H   t          d          }|d|fS |\  }	}
t          |	|
          }|}d}|rB	 ddl}|                                }n# t          $ r Y nw xY wt          ||pd|          \  }}n|}t          | ||||||          }t          ||||	           ||fS )
zLRefresh Nous runtime creds, rebuild the client, and replace the cache entry.Tr  Nr4  r   r:   r  rZ  r   r  r  r  r  r'  )r  r   r  get_event_looprk  r  r&  r,  )r-  rv   rZ  r   r  r  r  r  rZ  	fresh_keyfresh_base_urlr  r  current_loop_aior  r)  s                    r   _refresh_nous_auxiliary_clientr5    s    (d;;;GU{ 'I~^DDDKKL 	""""..00LL 	 	 	D	.{K<M2Ybccc!!  I FKLQQQQ;s   A 
AAc                  T    	 ddl m}  d | _        dS # t          t          f$ r Y dS w xY w)a  Monkey-patch ``AsyncHttpxClientWrapper.__del__`` to be a no-op.

    The OpenAI SDK's ``AsyncHttpxClientWrapper.__del__`` schedules
    ``self.aclose()`` via ``asyncio.get_running_loop().create_task()``.
    When an ``AsyncOpenAI`` client is garbage-collected while
    prompt_toolkit's event loop is running (the common CLI idle state),
    the ``aclose()`` task runs on prompt_toolkit's loop but the
    underlying TCP transport is bound to a *different* loop (the worker
    thread's loop that the client was originally created on).  If that
    loop is closed or its thread is dead, the transport's
    ``self._loop.call_soon()`` raises ``RuntimeError("Event loop is
    closed")``, which prompt_toolkit surfaces as "Unhandled exception
    in event loop ... Press ENTER to continue...".

    Neutering ``__del__`` is safe because:
    - Cached clients are explicitly cleaned via ``_force_close_async_httpx``
      on stale-loop detection and ``shutdown_cached_clients`` on exit.
    - Uncached clients' TCP connections are cleaned up by the OS when the
      process exits.
    - The OpenAI SDK itself marks this as a TODO (``# TODO(someday):
      support non asyncio runtimes here``).

    Call this once at CLI startup, before any ``AsyncOpenAI`` clients are
    created.
    r   AsyncHttpxClientWrapperc                     d S r   r   r&   s    r   <lambda>z(neuter_async_httpx_del.<locals>.<lambda>d  s    t r   N)openai._base_clientr8  __del__r  AttributeErrorr7  s    r   neuter_async_httpx_delr>  H  sR    4??????*;*;'''(   s    ''c                     	 ddl m} t          | dd          }|t          |dd          s|j        |_        dS dS dS # t
          $ r Y dS w xY w)u  Mark the httpx AsyncClient inside an AsyncOpenAI client as closed.

    This prevents ``AsyncHttpxClientWrapper.__del__`` from scheduling
    ``aclose()`` on a (potentially closed) event loop, which causes
    ``RuntimeError: Event loop is closed`` → prompt_toolkit's
    "Press ENTER to continue..." handler.

    We intentionally do NOT run the full async close path — the
    connections will be dropped by the OS when the process exits.
    r   )ClientStater  N	is_closedT)httpx._clientr@  r   CLOSED_stater   )r  r@  inners      r   r.  r.  i  s    ------	400WUK%F%F&-ELLL    s   6> 
AAc                     ddl } t          5  t          t                                                    D ]b\  }}|d         }|t          |           	 t          |dd          }|r|                     |          s
 |             S# t          $ r Y _w xY wt          	                                 ddd           dS # 1 swxY w Y   dS )zClose all cached clients (sync and async) to prevent event-loop errors.

    Call this during CLI shutdown, *before* the event loop is closed, to
    avoid ``AsyncHttpxClientWrapper.__del__`` raising on a dead loop.
    r   Nr)  )
inspectr,  ra  r-  rC   r.  r   iscoroutinefunctionr   r  )rG  r   r   r  r~  s        r   shutdown_cached_clientsrI  }  s0    NNN	  }224455 	 	JC1XF~ %V,,,"67D99 G$?$?$I$I HJJJ   !                 s6   AB<2BB<
BB<BB<<C C c                  $   t           5  g } t                                          D ]E\  }}|\  }}}|8|                                r$t	          |           |                     |           F| D ]
}t          |= 	 ddd           dS # 1 swxY w Y   dS )uK  Force-close cached async clients whose event loop is closed.

    Call this after each agent turn to proactively clean up stale clients
    before GC can trigger ``AsyncHttpxClientWrapper.__del__`` on them.
    This is defense-in-depth — the primary fix is ``neuter_async_httpx_del``
    which disables ``__del__`` entirely.
    N)r,  r-  rC   rA  r.  r]  )r/  r   r   r  _defaultcached_loops         r   cleanup_stale_async_clientsrM    s     
 # #
'--// 	' 	'JC,1)FHk&;+@+@+B+B&(000!!#&&& 	# 	#Cc""	## # # # # # # # # # # # # # # # # #s   A/BB	B	c           
          | t          | dd           t          | dd           fD ]5}|r1t          t          t          |dd          pd          d          r dS 6dS )Nr  r  r   r:   rw  TF)r   r0   r   )r  r#   s     r   _is_openrouter_clientrO    sr    	488'&(TX:Y:YZ   	(WS*b-I-I-OR)P)PRabb 	445r   cached_defaultc                 J    t          |           rdS t          |od|v           S )zFBest-effort check for cached clients that accept ``vendor/model`` IDs.Trx   )rO  r  )r  rP  s     r   #_cached_client_accepts_slash_modelsrR    s/    V$$ t83.#8999r   c                 :    |rd|v rt          | |          s|S |p|S )zKeep slash-bearing model IDs only for cached clients that support them.

    Mirrors the guard in resolve_provider_client() which is skipped on cache hits.
    rx   )rR  )r  rv   rP  s      r   _compat_modelrT    s5    
  &I&R`&a&a"N"r   c           
      j   d}|r*	 ddl }	|	                                }n# t          $ r Y nw xY wt          |          }
t	          | ||||||          }t
          5  |t          v rt          |         \  }}}|rX|duo||u o|                                 }|r!t          |||          }||fcddd           S t          |           t          |= n!t          |||          }||fcddd           S ddd           n# 1 swxY w Y   |}|s1t          t          |                     }|t          |          }|r|}t          | ||||||
|          \  }}||}t
          5  |t          vrt          t                    t          k    rpt!          t#          t                                                              \  }}t          |d                    t          |= t          t                    t          k    p|||ft          |<   nt          |         \  }}}ddd           n# 1 swxY w Y   ||p|fS )a  Get or create a cached client for the given provider.

    Async clients (AsyncOpenAI) use httpx.AsyncClient internally, which
    binds to the event loop that was current when the client was created.
    Using such a client on a *different* loop causes deadlocks or
    RuntimeError.  To prevent cross-loop issues, the cache validates on
    every async hit that the cached loop is the *current, open* loop.
    If the loop changed (e.g. a new gateway worker-thread loop), the stale
    entry is replaced in-place rather than creating an additional entry.

    This keeps cache size bounded to one entry per unique provider config,
    preventing the fd-exhaustion that previously occurred in long-running
    gateways where recycled worker threads created unbounded entries (#10200).
    Nr   r/  )r  rF  r  r  r  )r  r0  rk  r  r&  r,  r-  rA  rT  r.  r   rt   r   r  r   _CLIENT_CACHE_MAX_SIZEnextiterrC   )r`   rv   rZ  r   r  r  r  r  r3  r4  rZ  r)  cached_clientrP  rL  loop_ok	effectiveeffective_api_key_pe_pkr  r  r(  	evict_keyevict_entryrt  s                             r   rb  rb    s   < L 	""""..00LL 	 	 	D	%l33G!!  I 
 0 0%%9Fy9Q6M>; 0
  t+ 4#|34'11333 
  4 -mUN S SI()30 0 0 0 0 0 0 0  )777!),,)-OO	$i/)0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 06   (6x@@AA?',,C ($'!3"*	 	 	FM  "
 
	D 
	D-- -((,BBB-1$}7J7J7L7L2M2M-N-N*I{,[^<<<%i0 -((,BBB -3M:+Ni((+8+C(q
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 
	D 5)M))s8    
,,AC=8,C==DD"B6H$$H(+H(r   zhttps://api.openai.com/v1_AUX_DIRECT_API_BASE_URLSc           	         d}d}d}d}d}	| r"t          |           }
t          |
                    dd                                                    pd}t          |
                    dd                                                    pd}t          |
                    dd                                                    pd}t          |
                    dd                                                    pd}t          |
                    dd                                                    pd}	|p|}|	}dt          t                   d	t          t                   d
t
          t          t                   t          t                   f         fd}|r |||          \  }}|r |||          \  }}|rd||||fS |r|||||fS | r2|r	|rd||||fS |r|r|dk    r|||d|fS |r|dk    r|||||fS d|dd|fS d|dd|fS )a  Determine provider + model for a call.

    Priority:
      1. Explicit provider/model/base_url/api_key args (always win)
      2. Config file (auxiliary.{task}.provider/model/base_url)
      3. "auto" (full auto-detection chain)

    Returns (provider, model, base_url, api_key, api_mode) where model may
    be None (use provider default). When base_url is set, provider is forced
    to "custom" and the task uses that direct endpoint. api_mode is one of
    "chat_completions", "codex_responses", or None (auto-detect).
    Nr`   r:   rv   r   r  r  r   existing_baser   c                     | s| |fS t                               |                                                                           }|| |fS d|p|fS )Nrf   )ra  rp   rj   rk   )r   rc  target_bases      r   _expand_direct_api_aliasz>_resolve_task_provider_model.<locals>._expand_direct_api_aliask  s]     	'&&/33DJJLL4F4F4H4HII&&5+55r   rf   rb   )r  r   rp   rj   r   r	   )r  r`   rv   r   r  r  	cfg_modelr  cfg_api_keycfg_api_moder  rR  rU  rf  s                 r   r  r  A  s   & LILKL L066;??:r::;;AACCKt4455;;==E	;??:r::;;AACCKt+//)R8899??AAIT;??:r::;;AACCKt'iN$6x} 6Xc] 6W\]efi]jltuxly]yWz 6 6 6 6  J55hII( Z%=%=lL%Y%Y"l N7<MMM N7<MMM E 	ZK 	Z^\;HYYY 	WL 	W\V-C-C  tEVVV 	^LF22{L]]]~tT3DDD>4/@@@r         >@c                 `   | si S 	 ddl m}  |            }n# t          $ r i cY S w xY wt          |t                    r|                    di           ni }t          |t                    r|                    | i           ni }t          |t                    si }	 ddlm}  |            D ]q}|                    d          | k    rV|                    d          pi }t          |t                    r(t	          |          }|                    |           |c S  nrn# t          $ r Y nw xY w|S )u  Return the config dict for auxiliary.<task>, or {} when unavailable.

    For plugin-registered auxiliary tasks (see
    :meth:`hermes_cli.plugins.PluginContext.register_auxiliary_task`) the
    plugin's declared *defaults* are layered underneath the user's config
    so an unconfigured plugin task still works:

        plugin defaults  ←  config.yaml auxiliary.<task>  (user wins)

    Built-in tasks ignore this path (their defaults live in DEFAULT_CONFIG).
    r   r   	auxiliary)get_plugin_auxiliary_tasksr   defaults)
r   r   r  r"   r   rp   hermes_cli.pluginsrm  r  r   )	r  r   configauxr  rm  _entry	_defaultsr   s	            r   r  r    s     	111111   			)3FD)A)A
I&**["
%
%
%rC'1#t'<'<D#''$###"Kk4(( 
AAAAAA0022 	 	Fzz%  D(("JJz228b	i.. "!)__FMM+...!MMM )     s%    &&A>D D 
D+*D+r@  c                     | s|S t          |           }|                    d          }|'	 t          |          S # t          t          f$ r Y nw xY w|S )zPRead timeout from auxiliary.{task}.timeout in config, falling back to *default*.r  )r  rp   r   r  r6   )r  r@  r  raws       r   _get_task_timeoutrv    sm     ,T22K
//)
$
$C
	::I& 	 	 	D	Ns   ; AAc                     t          |           }|                    d          }t          |t                    rt          |          S i S )zFRead auxiliary.<task>.extra_body and return a shallow copy when valid.r  )r  rp   r"   r   )r  r  ru  s      r   _get_task_extra_bodyrx    sC    ,T22K
//,
'
'C#t CyyIr   >   minimax-oauthminimaxrU   c                 L    | t           v rdS |pd                                }d|v S )zDetect if an endpoint expects Anthropic-format content blocks.

    Returns True for known Anthropic-compatible providers (MiniMax) and
    any endpoint whose URL contains ``/anthropic`` in the path.
    Tr:   r   )_ANTHROPIC_COMPAT_PROVIDERSrk   )r`   r   	url_lowers      r   rd  rd    s5     ...tR&&((I9$$r   c           	         g }| D ]]}|                     d          }t          |t                    s|                    |           Cg }d}|D ]}|                     d          dk    r|                     d          pi                      dd          }|                    d          rv|                    d          \  }}	}
d	}d
|v r:d|v r6|                    d
d          d                             dd          d         }|                    dd||
dd           n|                    dd|dd           d}|                     d          dk    r|                     d          pi                      dd          }|                    d          rv|                    d          \  }}	}
d}d
|v r:d|v r6|                    d
d          d                             dd          d         }|                    dd||
dd           n|                    dd|dd           d}|                    |           |                    |ri |d|in|           _|S )as  Convert OpenAI ``image_url``/``video_url`` blocks to Anthropic format.

    Converts:
    - ``image_url`` blocks to Anthropic ``image`` blocks
    - ``video_url`` blocks to Anthropic ``video`` blocks (MiniMax M3 compat)

    Only touches messages that have list-type content with ``image_url`` or
    ``video_url`` blocks; plain text messages pass through unchanged.
    r  Fr$  	image_urlr8   r:   zdata:,z	image/pngrd   ;re   r   imager   )r$  
media_typer  )r$  r  )r$  r8   T	video_urlz	video/mp4video)rp   r"   ra  r]  rl   	partitionrm   )r
  ru  ro  r  new_contentchangedblockimage_url_valheaderrt  b64datar  video_url_vals                r   re  re    s    I EN EN'')$$'4(( 	S!!! =	* =	*Eyy  K//!&;!7!7!=2 B B5" M M ++G44 )6)@)@)E)E&FAw!,Jf}}%+\\#q%9%9!%<%B%B3%J%J1%M
&& '$,*4$+# #( (      && '$)#0# #( (    6""k11 "';!7!7!=2 B B5" M M ++G44 )6)@)@)E)E&FAw!,Jf}}%+\\#q%9%9!%<%B%B3%J%J1%M
&& '$,*4$+# #( (      && '$)#0# #( (    ""5))))GL8C8K888MMMMr   r  r  c	                    |||d}	t          ||          }
|
t          u rd}n|
|
}|ddlm}  ||          rd}|||	d<   |-|p| dk    rt	                      nd}t          | |          r||	d<   |rt                      }g }|D ]}}|                    d	          pi                     d
d          }|r"||v rt          	                    d|| |           Q|r|
                    |           |                    |           ~||	d<   t          |pi           }| dk    st          r5|                    dg                               t!                                 |r||	d<   |	S )zLBuild kwargs for .chat.completions.create() with model/provider adjustments.)rv   r
  r  Nr   r  r  rf   r:   r  r   r!  zK_build_call_kwargs: duplicate tool name '%s' removed (provider=%s model=%s)r  r  r   r  )r   ru   r  r  r  rd  r,  rp   r   rb  r  r]  r   r   
setdefaultextendr   )r`   rv   r
  r  r  r  r  r  r   r   fixed_temperaturer  _effective_base_seen_deduped_t_tnamemerged_extras                     r   rc  rc  ?  s     F 5UHEE,,,		&' DDDDDD##E** 	K +} # 
*2h*>*>$&&&B 	 )?CC 	.#-F<  # UU 	  	 BffZ((.B33FB??F &E//-He  
  "		&!!!OOB"w 
(b))L6.++223D3F3FGGG ,+|Mr   r  c           
      `   | t          d|pd d          	 | j        }|rt          |d         d          st          d          nf# t          t          t
          f$ rL}t          |           j        }t          |           dd         }t          d|pd d	| d
|d          |d}~ww xY w| S )a3  Validate that an LLM response has the expected .choices[0].message shape.

    Fails fast with a clear error instead of letting malformed payloads
    propagate to downstream consumers where they crash with misleading
    AttributeError (e.g. "'str' object has no attribute 'choices'").

    See #7264.
    Nr\  r  z: LLM returned None responser   rE  zmissing choices[0].messagex   z&: LLM returned invalid response (type=z): ug   . Expected object with .choices[0].message — check provider adapter or custom endpoint compatibility.)	rk  rZ  r  r=  r6   
IndexErrorr$  r(   r   )r  r  rZ  r   response_typeresponse_previews         r   rf  rf    s    EEEE
 
 	

" 	?ggaj)<< 	? !=>>>	?Iz2   X/x==#.9 9 9"9 9'79 9 9
 

 	 Os   .A B+AB&&B+)
r`   rv   r   r  r  r  r  r  r  r  c                v   t          | ||||          \  }}}}}t          |           }|                    |pi            | dk    r~t          |dk    r|n||p||p||p|d          \  }}}|9|dk    r3|s1t                              d|           t          d|d          \  }}}|t          d|  d	| d
          |p|}nt          ||||||          \  }}||pd                                	                                }|r,|dvr(t          d| d|
                                 d          |s2t                              d| pd|           t          d|          \  }}|t          d|  d	| d
          |
|
nt          |           }t          t          |d|          pd          }| r-t                              d| |pd|pd|r	d|vrd| nd           t          ||||||	|||p|	  	        }t          t          |dd          pd          }t!          ||          rt#          |d                   |d<   	 	 t%           |j        j        j        d;i ||           S # t,          $ r]}t/          |          s t                              d| pd|           t%           |j        j        j        d;i ||           cY d}~S d}~ww xY w# t,          $ rX}d|v rt1          |          rt3          |          }|                    dd           t                              d| pd           	 t%           |j        j        j        d;i ||           cY d}~S # t,          $ rS}t          |          }t7          |          s't9          |          st;          |          s	d|v sd|v s |}|}Y d}~nd}~ww xY wt          |          }d |v od!t          t          |dd                    v } |d|v sd|v st=          |d          s| r|                    dd           |                    d"d           	 t%           |j        j        j        d;i ||           cY d}~S # t,          $ r:}t7          |          st9          |          st?          |          s |}Y d}~nd}~ww xY w|d#k    ptA          |d$          }!tC          |          r|!rtE          | dk    |#                    d%          &          }"|"r|"|#                    d%          k    r{t                              d'| pd|#                    d%          |"           |"|d%<   	 t%           |j        j        j        d;i ||           cY d}~S # t,          $ r}|}Y d}~nd}~ww xY w|d#k    ptA          |d$          }#t7          |          r|#rtI                      rtK          |pd#|d||||| dk    (          \  }$}%|$t                              d)| pd           |%r|%|#                    d%          k    r|%|d%<   	 t%           |$j        j        j        d;i ||           cY d}~S # t,          $ rI}t;          |          s.t7          |          st9          |          st?          |          s |}Y d}~nd}~ww xY wt;          |          r|#rtK          |pd#|d||||| dk    (          \  }$}%|$gt                              d*| pd           |%r|%|#                    d%          k    r|%|d%<   t%           |$j        j        j        d;i ||           cY d}~S t;          |          rU|d+vrQ|#sOtM          |          r@t                              d,| pd|           tO          | |||||||||||	||-          cY d}~S tQ          |||          }&t          t          |d.d          pd          }'|&r~t;          |          st7          |          st?          |          rP|}(t?          |          rt7          |          sr	 t%           |j        j        j        d;i ||           cY d}~S # t,          $ r:}t;          |          st7          |          st?          |          s |}(Y d}~nd}~ww xY wtS          |&|(|'/          rt                              d0| pd|&tU          |(          j+                   	 tO          | |||||||||||	||-          cY d}~S # t,          $ rK})t7          |)          st;          |)          st?          |)          rtS          |&|)           |)}n Y d})~)nd})~)ww xY wt7          |          pt9          |          pt?          |          }*|d+v }+t7          |          pt9          |          },|*r<|+s|,r7t7          |          r$d1}-tY          tQ          |||          p|           nt?          |          rd2}-nd3}-t                              d4| pd|-||           d5\  }.}/}0|+rt[          || |-6          \  }.}/}0n0t]          | |pd|-6          \  }.}/}0|.t_          || |-6          \  }.}/}0|.`t          |0|/||||	||t          t          |.dd          pd          	  	        }1t%           |.j        j        j        d;i |1|           cY d}~S t                              d7| pd|-|           t9          |          r=	 ta          |           n,# t,          $ r t          1                    d8d9:           Y nw xY w d}~ww xY w)<a  Centralized synchronous LLM call.

    Resolves provider + model (from task config, explicit args, or auto-detect),
    handles auth, request formatting, and model-specific arg adjustments.

    Args:
        task: Auxiliary task name ("compression", "vision", "web_extract",
              "session_search", "skills_hub", "mcp", "title_generation").
              Reads provider:model from config/env. Ignored if provider is set.
        provider: Explicit provider override.
        model: Explicit model override.
        messages: Chat messages list.
        temperature: Sampling temperature (None = provider default).
        max_tokens: Max output tokens (handles max_tokens vs max_completion_tokens).
        tools: Tool definitions (for function calling).
        timeout: Request timeout in seconds (None = read from auxiliary.{task}.timeout config).
        extra_body: Additional request body fields.

    Returns:
        Response object with .choices[0].message.content

    Raises:
        RuntimeError: If no provider is configured.
    rQ  rb   FrY  NDVision provider %s unavailable, falling back to auto vision backendsr`   rv   rZ  $No LLM provider configured for task=
 provider=. Run: hermes setupr[  r:   >   rb   rf   r   
Provider ':' is set in config.yaml but no API key was found. Set the U_API_KEY environment variable, or switch to a different provider with `hermes model`.BAuxiliary %s: provider %s unavailable, trying auto-detection chainr  r7  r   zAuxiliary %s: using %s (%s)%sr@  r   z at r_  r
  z_Auxiliary %s: transient transport error; retrying once on the same provider before fallback: %sr  zEAuxiliary %s: provider rejected temperature; retrying once without itr  r  1210r   r  r  r?  rv   rQ  r]  z[Auxiliary %s: model %r no longer in Nous catalog; retrying with refreshed recommendation %r)r-  rv   rZ  r   r  r  r  r  zSAuxiliary %s: refreshed Nous runtime credentials after paid account check, retryingzDAuxiliary %s: refreshed Nous runtime credentials after 401, retrying>   Nr:   rb   zAAuxiliary %s: refreshed %s credentials after auth error, retrying)r  r=  rR  rS  rT  rU  r  r  r
  r  r  r  rV  rW  r  rE  z@Auxiliary %s: recovered %s via credential-pool rotation after %sru  r  connection errorz,Auxiliary %s: %s on %s (%s), trying fallbackr  rw  zoAuxiliary %s: %s on %s and all fallbacks exhausted (fallback_chain + main agent model). Raising original error.z7Auxiliary: cache eviction after connection error failedTr*  r   )2r  rx  r  ra  r   rb  rk  rb  rj   rk   upperr  rv  r   r   rc  rd  re  rf  r  r  rj  r   r  r"  r   r  r  r  r  r   r  r0   r(  ra  rp   r  r5  rt  rk  rD  rQ  r$  r(   rK  r  r  r  r-  r   )2r  r`   rv   r   r  r  r
  r  r  r  r  r  r=  rR  rS  rT  rU  rW  effective_providerr  r  	_explicitrV  
_base_infor   _client_basetransient_err	first_errrj  	retry_errretry_err_strerr_str_is_zai_param_error_heal_is_noushealed_modelclient_is_nousrefreshed_clientrefreshed_modelpool_provider_client_api_keyrecovery_err
retry2_errshould_fallbackis_autois_capacity_errorrw  r  r  fb_label	fb_kwargss2                                                     r   call_llmr    s%   N a}hxa2 a2]~'8:JL]/55
 0b111x2P*;v*E*E&&8 )E&2($/3
 3
 3
/FK >/699BS9NNV!   7U$ 7 7 73
 >%t % %GX % % %   /C2C0&$&%
 
 
 > +0b7799??AAI Y.NNN"X X X*3//*;*;X X X   % \` NF,=? ? ?&8l&[&[&[#>%t % %GX % % %& & & $+#6<Md<S<S WVZ1BCCIrJJJ c3,68Py,6a<z;Y;Y(J(((_a	c 	c 	c  ;J.;O00	2 2 2F wvz266<"==L$%6EE U@
ASTTzR	@).'.8888$@ @ @ 		@ 		@ 		@0?? KK8  
 *.'.8888$@ @ @ @ @ @ @ @		@  { { {F""'H'S'S"<<L]D111KKW  &-2FK+2BB\BBDJ J J J J J J J & & & #I &i00+I66 &i00 $}44.-??%	%&" i.. g Cc'&*b"A"ABBB 	 !G##&'11.y,GG 2" 2 JJ|T***JJ.555&-2FK+2<<V<<dD D D D D D D D & & & *)44 8LY8W8W [opy[z[z %						& ' S$Z1QRR 	 %Y// 	*M 	*:(vzz'7J7JL L LL *

70C0C C C@NFFJJw$7$7  
 #/w*16/6@@@@$H H H H H H H H  * * * )IIIIII*
 ' S$Z1QRR 	
 i((!	*!	* ;<<!	*
 1O0:F! *(*)8+	1 	1 	1-o  +iNF   # 6&**W:M:M'M'M&5F7O*1@(-9@JJ6JJDR R R R R R R R  * * *&y11,Y77 0	:: 0	::	  )IIIIII* )$$ 	N 	N0N0:F! *(*)8+	1 	1 	1-o  +b NF, , ," 6&**W:M:M'M'M&5F7O-<$)5<FFvFFN N N N N N N N 9%% 	%-???& @,->?? WNF$5   1&7#1&7%5&7!- +% +)&7)=        $ 33Df[ghhh
 gfi<<BCC -	nY77 -	;LY;W;W -	[opy[z[z -	$L $I.. -7H7S7S --16/6@@@@$H H H H H H H H  - - -*955 9J99U9U YmnwYxYx #,LLLLLL- &m\Rabbb !VNFM43E3E3N  4!*;'5*;)9*;%1$/!)$/#-#*;-A          !    **55 
9S9S 3J??.}jIII$.		 "				> i(( /#I../#I.. 	 $'99 .i88[<PQZ<[<[ 2	 2	+< 2	 ++ ,(
 )./@&Wcdddyhy    &i00 ,%+KKF0A9N N N -=)Ix @0E%tF1< 1< 1<-	8XX 1O+5vf1F 1F 1F-	8X$4R)45@ 5@ 5@1Ix $.h +
):3 J!C!C!IrJJL L L	 .5IN.5BB	BBDJ J J J J J J J
 NNO(9    	** 	,,-f5555 , , ,V&*  , , , , ,, 	w	{s  $I+ +
K5AKKK KK l8 Al36$M l8 
N=*A	N83l38N==A>l3<$Q& l8&
R*00R% l3%R**B$l3$U93l89
VV
l3
VBl3'$Yl8
Z$?Zl3Z$$Bl3;l8Al3l8%Bl3)$al8
b0bl3bAl3d :l8 
e
Ael3eE,l3l8.l36ll3&l/,l3.l//l33l8c                    ddl }| j        d         j        }|j        pd                                }|r<|                    dd||j        |j        z                                            }|r|S g }dD ]i}t          ||d          }|rTt          |t                    r?|                                r+||vr'|                    |                                           jt          |dd          }|rt          |t                    r|D ]}	t          |	t                    r|	                    d          p)|	                    d	          p|	                    d
          }
|
rO|
|vrK|                    t          |
t                    r|
                                nt          |
                     |rd                    |          S dS )u  Extract content from an LLM response, falling back to reasoning fields.

    Mirrors the main agent loop's behavior when a reasoning model (DeepSeek-R1,
    Qwen-QwQ, etc.) returns ``content=None`` with reasoning in structured fields.

    Resolution order:
      1. ``message.content`` — strip inline think/reasoning blocks, check for
         remaining non-whitespace text.
      2. ``message.reasoning`` / ``message.reasoning_content`` — direct
         structured reasoning fields (DeepSeek, Moonshot, NovitaAI, etc.).
      3. ``message.reasoning_details`` — OpenRouter unified array format.

    Returns the best available text, or ``""`` if nothing found.
    r   Nr:   zz<(?:think|thinking|reasoning|thought|REASONING_SCRATCHPAD)>.*?</(?:think|thinking|reasoning|thought|REASONING_SCRATCHPAD)>)flags)r  reasoning_contentreasoning_detailsr  r  rF  z

)rerZ  rE  r  rj   subDOTALL
IGNORECASEr   r"   r   r]  ra  r   rp   rm  )r  r  ro  r  cleanedreasoning_partsr  rB  detailsdetailr  s              r   extract_content_or_reasoningr    s    III

1

%C{ b''))G 	&&L ry2=8	  
 

 %'' 	  	N "$O3 0 0c5$'' 	0:c3'' 	0CIIKK 	0C<V<V""399;;///c.55G 	j:gt,, 	j 	j 	jF&$'' jJJy)) *zz),,*zz&)) 
  jwo==#**jRU>V>V+h7==???\_`g\h\hiii ,{{?+++2r   c                  K   t          | ||||          \  }}}}}t          |           }|                    |pi            | dk    r~t          |dk    r|n||p||p||p|d          \  }}}|9|dk    r3|s1t                              d|           t          d|d          \  }}}|t          d|  d	| d
          |p|}nt          ||d|||          \  }}||pd                                	                                }|r,|dvr(t          d| d|
                                 d          |s2t                              d| pd|           t          dd          \  }}|t          d|  d	| d
          |
|
nt          |           }t          t          |dd          pd          }t          ||||||	|||p|	  	        }t!          ||          rt#          |d                   |d<   	 	 t%           |j        j        j        d8i | d{V |           S # t,          $ rc}t/          |          s t                              d| pd|           t%           |j        j        j        d8i | d{V |           cY d}~S d}~ww xY w# t,          $ r}d|v rt1          |          rt3          |          }|                    dd           t                              d| pd           	 t%           |j        j        j        d8i | d{V |           cY d}~S # t,          $ rS}t          |          }t7          |          s't9          |          st;          |          s	d|v sd|v s |}|}Y d}~nd}~ww xY wt          |          }d|v odt          t          |dd                    v }|d|v sd|v st=          |d          s|r|                    dd           |                    dd           	 t%           |j        j        j        d8i | d{V |           cY d}~S # t,          $ r:}t7          |          st9          |          st?          |          s |}Y d}~nd}~ww xY w|dk    ptA          |d           } tC          |          r| rtE          | dk    |#                    d!          "          }!|!r|!|#                    d!          k    rt                              d#| pd|#                    d!          |!           |!|d!<   	 t%           |j        j        j        d8i | d{V |           cY d}~S # t,          $ r}|}Y d}~nd}~ww xY w|dk    ptA          |d           }"t7          |          r|"rtI                      rtK          |pd|d|||| dk    $          \  }#}$|#t                              d%| pd           |$r|$|#                    d!          k    r|$|d!<   	 t%           |#j        j        j        d8i | d{V |           cY d}~S # t,          $ rI}t;          |          s.t7          |          st9          |          st?          |          s |}Y d}~nd}~ww xY wt;          |          r|"rtK          |pd|d|||| dk    $          \  }#}$|#mt                              d&| pd           |$r|$|#                    d!          k    r|$|d!<   t%           |#j        j        j        d8i | d{V |           cY d}~S t;          |          rZ|d'vrV|"sTtM          |          rEt                              d(| pd|           tO          | ||||||||||	||)           d{V cY d}~S tQ          |||*          }%t          t          |d+d          pd          }&|%rt;          |          st7          |          st?          |          r[|}'t?          |          rt7          |          sx	 t%           |j        j        j        d8i | d{V |           cY d}~S # t,          $ r:}t;          |          st7          |          st?          |          s |}'Y d}~nd}~ww xY wtS          |%|'|&,          rt                              d-| pd|%tU          |'          j+                   	 tO          | ||||||||||	||)           d{V cY d}~S # t,          $ rK}(t7          |(          st;          |(          st?          |(          rtS          |%|(           |(}n Y d}(~(nd}(~(ww xY wt7          |          pt9          |          pt?          |          })|d'v }*t7          |          pt9          |          }+|)r{|*s|+rvt7          |          r"d.},tY          tQ          ||          p|           nt?          |          rd/},nd0},t                              d1| pd|,||           d2\  }-}.}/|*rt[          || |,3          \  }-}.}/n0t]          | |pd|,3          \  }-}.}/|-t_          || |,3          \  }-}.}/|-t          |/|.||||	||t          t          |-dd          pd          	  	        }0ta          |-|.pd| dk    4          \  }1}2|2r|2|0#                    d!          k    r|2|0d!<   t%           |1j        j        j        d8i |0 d{V |           cY d}~S t                              d5| pd|,|           t9          |          r=	 tc          |           n,# t,          $ r t          2                    d6d7           Y nw xY w d}~ww xY w)9zqCentralized asynchronous LLM call.

    Same as call_llm() but async. See call_llm() for full documentation.
    rQ  rb   TrY  Nr  r  r  r  r  rm  r:   >   rb   rf   r   r  r  r  r  r  )rZ  r   r_  r
  zgAuxiliary %s (async): transient transport error; retrying once on the same provider before fallback: %sr  zMAuxiliary %s (async): provider rejected temperature; retrying once without itr  r  r  r   r  r  r?  rv   r  zcAuxiliary %s (async): model %r no longer in Nous catalog; retrying with refreshed recommendation %r)r-  rv   rZ  r   r  r  r  z[Auxiliary %s (async): refreshed Nous runtime credentials after paid account check, retryingzLAuxiliary %s (async): refreshed Nous runtime credentials after 401, retrying>   Nr:   rb   zIAuxiliary %s (async): refreshed %s credentials after auth error, retrying)r  r=  rR  rS  rT  rU  r  r
  r  r  r  rV  rW  r7  r  rE  zHAuxiliary %s (async): recovered %s via credential-pool rotation after %sru  r  r  z4Auxiliary %s (async): %s on %s (%s), trying fallbackr  r  r  zwAuxiliary %s (async): %s on %s and all fallbacks exhausted (fallback_chain + main agent model). Raising original error.z?Auxiliary (async): cache eviction after connection error failedr*  r   )3r  rx  r  ra  r   rb  rk  rb  rj   rk   r  r  rv  r   r   rc  rd  re  rf  r  r  rj  r   r  r"  r   r  r  r  r  r   r  r0   r(  ra  rp   r  r5  rt  rn  rD  rQ  r$  r(   rK  r  r  r  r  r-  r   )3r  r`   rv   r   r  r  r
  r  r  r  r  r  r=  rR  rS  rT  rU  rW  r  r  r  r  rV  r  r   r  r  rj  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  rw  r  r  r  r  async_fbasync_fb_models3                                                      r   async_call_llmr    s     & a}hxa2 a2]~'8:JL]/55
 0b111x2P*;v*E*E&&8 )E&2($/3
 3
 3
/FK >/699BS9NNV!   7U$7 7 73
 >%t % %GX % % %   /C2C0&$&
 
 
 >*0b7799??AAI Y.NNN"X X X*3//*;*;X X X  
 % R` NF,=? ? ?&8D&Q&Q&Q#>%t % %GX % % %& & & $+#6<Md<S<S
 wvz266<"==L;J.;O2!2	4 4 4F %%6EE U@
ASTTza	F)4fk-4>>v>>>>>>>>F F F 		F 		F 		F0?? KK@  
 *4fk-4>>v>>>>>>>>F F F F F F F F		F  P P PF""'H'S'S"<<L]D111KK_  &-8&+18HH<HHHHHHHH$P P P P P P P P & & & #I%i00+I66 &i00 $}44.-??%	%& i.. g Cc'&*b"A"ABBB 	 !G##&'11.y,GG 2" 2 JJ|T***JJ.555&-8&+18BB6BBBBBBBBDJ J J J J J J J & & & *)44 8LY8W8W [opy[z[z %						& ' U$\3STT 	 %Y// 	*M 	*:(vzz'7J7JL L LL *

70C0C C C@NFFJJw$7$7  
 #/w*1<fk5<FFvFFFFFFFFN N N N N N N N  * * * )IIIIII*
 ' U$\3STT 	
 i(( 	* 	* ;<< 	*
 1O0:F!*(*8+1 1 1-o  +qNF   # 6&**W:M:M'M'M&5F7O*1F.3?FPPPPPPPPPPRVX X X X X X X X  * * *&y11,Y77 0	:: 0	::	  )IIIIII* )$$ 	T 	T0N0:F!*(*8+1 1 1-o  +j NF, , ," 6&**W:M:M'M'M&5F7O-B*/;BLLVLLLLLLLLdT T T T T T T T 9%% 	%-???& @,->?? _NF$5   8&7#1&7%5&7 +% +)&7)=              " 33Df[ghhhgfi<<BCC '	nY77 '	;LY;W;W '	[opy[z[z '	$L $I.. -7H7S7S --1<fk5<FFvFFFFFFFFN N N N N N N N  - - -*955 9J99U9U YmnwYxYx #,LLLLLL- &m\Rabbb ^NFM43E3E3N  !;!*;'5*;)9*;$/!)$/#-#*;-A" " "             !   )*55 
9S9S 3J??.}jIII$.		 "					 i(( /#I../#I.. 	 $'99-i88[<PQZ<[<[ 1	 1	+< 1	 ++ ,((./@&II^M^    &i00 ,%+KKN0A9N N N -=)Ix @0E%tF1< 1< 1<-	8XX 1O+5vf1F 1F 1F-	8X$4R)45@ 5@ 5@1Ix $.h +
):3 J!C!C!IrJJL L L	 ,<x~2$(:J, , ,(. " 8n	g8N8N&N&N)7Ig&-:(-3:GGYGGGGGGGGO O O O O O O O NNO(9    	** 	,,-f5555 , , ,^&*  , , , , ,, 	aPs  9*H$ $
J.AJJJ JJ m"Am5*L%m"%
N/A	M=8m=NA>m*P1+m"1
Q5;0Q0+m0Q55B$m*U
m"

U UmU  Bm7*X'!m"'
Y:1?Y50m5Y::Bmm"A#m?m"Bm	*`93m"9
a=0a83m8a==Am!c+%m"+
e 5Ad;6m;e  F+m+m"1.m l0/m0&mmmmm"r   )r:   r0  r  r[  )Nru  )Nr  )r  rv  )NFFNNNNF)NFNNNNF)NNNNN)NNNrj  NN)r+   r   loggingr   rc  r2  pathlibr   typesr   typingr   r   r   r   r	   r
   r  r   r   r   r   r   r   r$  __annotations__r   r   agent.credential_poolr-   r   r.   hermes_constantsr/   utilsr0   r1   r2   r3   	getLoggerr(   r   r  r7   r   rG   r  ro   rt   objectru   r~   r   r   r   r   r   r   r   r   r   r   	frozensetr   r   r   r   r   r   r   r   agent.portal_tagsr   r   r   NOUS_EXTRA_BODYr   rL  rX  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,  rE  rN  rP  r\  ra  rg  rn   ri  rc  rj  rk  rl  rn  rp  r  r  r  r  r  r  r  r  r:  _AUTO_PROVIDER_LABELSr  r  r  r  r  r  r  r  rK  r9  r  r  r   r  r  r  r  r  r  r   r"  r(  r0  r-  r:  r<  rD  rQ  ra  r   rk  rn  rt  r  r  r  r  r  r  r  r  r  r  r  r  r  r
  r  r  ra  r  r  r-  Lockr,  rV  r&  r,  r5  r>  r.  rI  rM  rO  rR  rT  rb  ra  r  _DEFAULT_AUX_TIMEOUTr  rv  rx  r|  rd  re  rc  rf  r  r  r  r   r   r   <module>r     s~"  ( ( (T   				            ! ! ! ! ! ! B B B B B B B B B B B B B B B B 7 7 7 7 7 7 7 7 7 7  $( 8D> ( ( ($    , , , , , , , ,& 
 + + + + + + - - - - - - 0 0 0 0 0 0 x x x x x x x x x x x x		8	$	$# 3 4    3      hX  E	
 E E 
5 E E U M   #   !" \#$ '&!"'%=   D9hsm 9 9 9 9 92 "688 & # # #6(3- 6D 6 6 6 6,hsm , , , , , %) ![ [8C= [HSM [T [ [ [ [& # C=sm     0 # )-	  C=sm "&	
 e_   :FS FS F F F F( '*-1,$/)%9 9 %tCH~   " 0U d38n T T T + + c3h    (1y2 ( ( 9    <7   Y999::      :1 1t 1t 1 1 1 1n } 
sTz d      D C C C C C)$ ) ) ) ) #"$$   4    4 -D 9 !/##k1 > $C $DcN $ $ $ $N# #    < tXc]/B)C     s x}    ." " " " " ". .# . .c . . . .(\
 \
 \
 \
 \
 \
 \
 \
~# # # # # # # #" " " " " " " "$D D D D D D D D# # # # # # # #
6 6 6 6 6 6 6 6&X
 X
 X
 X
 X
 X
 X
 X
v# # # # # # # #
        D D D D D D D D# # # # # # # #
	6 	6 	6 	6 	6 	6 	6 	6# $    B #O OOO O 	O
 smO 	O O O Od#$ # # # #LD S    (H H H H H
 8=    %PSUXPX/AZ    44HU38_$= 4 4 4 4n((3- ( ( ( (Vo5&)98C=)H#I o o o olS Sc S ShW]N^`hil`mNmHn S S S S*
4# 
4 
4 
4 
4Q Qd QuXf-=x}-L'M Q Q Q Qh&&"*3-&c]& & & &R#    <S    6 !        S            s            6 6 666 	6
 6 6 
6 6 6 68       /8x}hsmXc]'R!S /8 /8 /8 /8d#    
   :     $0#eHSM8C=$@A 0# 0# 0# 0#f;s ;uXc]HSM5Q/R ; ; ; ;4&;s &;uXc]HSM-I'J &; &; &; &;V  &*'+"o o oC=o smo  }	o
 smo 8C=(3-'(o o o od-c -cS -cE(3-RU:V4W -c -c -c -cb $*!*	   ] (4S>*B tCQTH~    4T%[    R ! )+ d3:& + + +-/ $sEz* / / / ""    	2S 	2S 	2 	2 	2 	2 s % D    &# $     
 
s 
(3- 
4 
 
 
 
 % % % %%9 % % % % %P	D 	 	 	 	"i "D " " " "J#i #D # # # #LNy NT N N N N&	 d    $ 3 4    D?9 ? ? ? ? ?%9 % % % % %P)C )D ) ) ) )* #  $        L .2& & && 4S>*& 		& & & &*Y 4S>     .2( ((( 4S>*( c]	( ( ( (V TV . . .S .y .S .Z^ . . . .b7
3-7 7 SM	7
  }7 sm7  }7 4S>*7 #7 7 %7 7 D>7 7 7  	!7 7 7 7t6
3-6 6 SM	6
  }6 sm6  }6 #6 6 %6 6 D>6 6 6 	6 6 6 6r7C 7D 7 7 7 7x !0 00
0 0 8C=(3-,-	0 0 0 0j .7 .7.7
.7 .7 8C=(3-,-	.7 .7 .7 .7h 8 8
88 8 8C=(3-,-	8 8 8 8z  "!	 C= sm c]	
 c]   &v vc3h 8 vE(SYJZ\deh\iJiDj v v v vH>. >. >. >. >. >. >.B	(3- 	3 	8TW= 	 	 	 	 ! -1I
 I
I
I
 I
 	I

 I
 I
 I
 4S>*I
 I
 8C=(3-'(I
 I
 I
 I
^  .2  
 4S>* 8FXc]*+	   2`d   # XdSVX[S[nE]    & # hsm     >-# -3 - - - -   C= 8C=(3-'(   .Cs Ct C C C CtCy    4 #d* #!d* d* d*smd*C=d* sm	d*
 c]d* d* 8C=(3-#67d* d* d* d*N;$ ; ; ; ; FJ ! ! !c !Xc] !d ! ! ! !T %'tE5L! & & &#Y^%%   #!"-1t t tt t sm	t
 c]t smt 4S>*t t t t t t  lp G G GE G3 GxPS} Geh Gtx G G G G& #!"-1) ) )) C=) 	)
 sm) c]) sm) 4S>*) ) 8C=(3-'() ) ) )X   BS T    (   6# # # #&# $    : :Xc] :W[ : : : :## #hsm #Xc] #W_`cWd # # # # -1j* j*j*j* j* 	j*
 j* j* 4S>*j* j* 8C=(3-'(j* j* j* j*t )- 4S>    KA KA
KAKA KA 	KA
 KA 3x}hsmXc]JKKA KA KA KA\  )S )T#s(^ ) ) ) )X 3G  C % 5    s tCH~     (i(R(R(RSS 	%C 	%3 	%4 	% 	% 	% 	%Q$ Q4 Q Q Q Qr $( $ !%"U UUU U %	U
 U D>U U U smU 
U U U Up S  s    @ Q -1Q Q Q
Q Q 	Q
 Q Q 4S>*Q Q Q Q Q Q Q 	Q Q Q Qh5c 5 5 5 5r { -1{ { {
{ { 	{
 { { 4S>*{ { { { { { { 	{ { { { { {r   