
    iC                       U d Z ddlmZ ddlZddlZddlZddlZddlZddl	m
Z
 ddlmZ ddlmZmZmZ ddlmZ de Zd	Ze d
ZdZg dZg dZg dZded<   daded<   g dZded<   daded<   ddZg dZ ded<   ddZ!i dg ddg dd  e            d!d!gd"g d#d$g d%d&g d'd(g d)d* e!            d+g d,d-g d.d/g d0d1d2d3gd4g d0d5g d6d7d8d9gd:g d6g d;g d<g d=d>gg d?g d@g dAg dBg dCg dDg dEg dFg dGZ"dHedI<   dJ eD             e"dK<   ddQZ#dddVZ$ddXZ%dd\Z&d]Z'd^ed_<   da(d`eda<   ddbZ)dcZ*ddZ+d^ede<   i Z,dfedg<   	 	 ddidjddnZ-ddoZ.ddsZ/diddRdidtddwZ0 G dx dye          Z1g  e1ddzd{           e1d|d}d~           e1ddd           e1ddd           e1d dd           e1ddd           e1ddd           e1d+dd           e1ddd           e1d"dd           e1d!dd           e1ddd           e1d$dd           e1d&dd           e1ddd           e1d*dd           e1d(dd           e1d-dd           e1d/dd           e1d1dd           e1d5dd           e1d7dd           e1d:dd           e1ddd           e1ddd           e1ddd           e1ddd           e1ddd           e1ddd           e1dddæ           e1dddƦ           e1dddɦ           e1dKddʦ          Z2ded<   d̈́ e2D             Z3de3d<   i dd(dd(dd(dd(dd"dd"dd"dd"dd!dd!dd$dd$dd$dd-d4d-dd/dd/i dd1dd1dddddddddd:dd:dd7dd7dd7ddddddddddddi ddddKddKddKdddddddddddddddddd&dd&ddd dddi ddddddddddddddēd	dēd
dēddēdd*dd*dd*dd+dd+dd+dd+ddddddZ4ddZ5ddZ6ddZ7	 ddidjdÐdZ8didjdĐdZ9ddZ:ddZ;	 ddidjdÐdZ<didjdĐdZ=i Z>d ed!<   dŐd#Z?	 	 dƐdǐd)Z@	 	 	 ddidjdɐd.ZA	 ddidjdʐd/ZBdd0ZCdːd2ZDdidjd̐d3ZE eFe3G                                           eFe4G                                          z  d|dhz  ZHd4ed5<   d͐d7ZIdΐd:ZJdd;ZKdidjdϐd<ZLdАd=ZMdѐd@ZN eOh dA          ZPdҐdDZQdӐdFZRdӐdGZSdԐdHZTdՐdIZUdՐdJZVdKZWdLedM<   d֐dNZXdאdOZYd֐dPZZd֐dQZ[dؐdSZ\ddTZ] eOh dU          Z^dVedW<   dِdYZ_didjdڐdZZ`dېdܐd\Zadݐd_ZbdސdaZcdߐdbZd	 ddddZei afdeedf<   dgagdledh<   diZhdddkZiddlZjddmZkdddoZl	 	 	 dddqZm	 	 	 dddrZn	 	 	 dddsZo	 dddwZp	 	 dddxZqdddyZri dzd{d|d{d}d{d~d{dddddddddddddd{dddddd{dd{ddddddddddddddddddZs	 	 dddZtdddddZuddZvddZwdddddZxdZyddZzddZ{ddZ|dddddZ}	 	 dddZ~dېdܐdZ	 	 dddZdiZddZdidddZddZ	 	 ddidjddZddddddZdS (  u   
Canonical model catalogs and lightweight validation helpers.

Add, remove, or reorder entries here — both `hermes setup` and
`hermes` provider-selection will pick up the change automatically.
    )annotationsN)get_close_matches)Path)Any
NamedTupleOptional)__version__zhermes-cli/zhttps://api.githubcopilot.com/modelszvscode/1.104.1)minimallowmediumhigh)r   r   r   )#moonshotai/kimi-k2.6recommendedanthropic/claude-opus-4.7 anthropic/claude-opus-4.6r   anthropic/claude-sonnet-4.6r   )zqwen/qwen3.6-plusr   )anthropic/claude-sonnet-4.5r   anthropic/claude-haiku-4.5r   )zopenrouter/elephant-alphafree)zopenrouter/owl-alphar   )openai/gpt-5.5r   openai/gpt-5.4-minir   )xiaomi/mimo-v2.5-pror   )xiaomi/mimo-v2.5r   )ztencent/hy3-preview:freer   openai/gpt-5.3-codexr   )z!google/gemini-3-pro-image-previewr   )google/gemini-3-flash-previewr   google/gemini-3.1-pro-previewr   $google/gemini-3.1-flash-lite-previewr   )qwen/qwen3.5-plus-02-15r   )qwen/qwen3.5-35b-a3br   )stepfun/step-3.5-flashr   minimax/minimax-m2.7r   )minimax/minimax-m2.5r   )minimax/minimax-m2.5:freer   )z-ai/glm-5.1r   )z-ai/glm-5v-turbor   )z-ai/glm-5-turbor   )zx-ai/grok-4.20r   )!nvidia/nemotron-3-super-120b-a12br   )z&nvidia/nemotron-3-super-120b-a12b:freer   )z#arcee-ai/trinity-large-preview:freer   )arcee-ai/trinity-large-thinkingr   )openai/gpt-5.5-pror   )openai/gpt-5.4-nanor   list[tuple[str, str]]OPENROUTER_MODELSzlist[tuple[str, str]] | None_openrouter_catalog_cache)r   )zalibaba/qwen3.6-plusr   )zzai/glm-5.1r   r,   r   r   r   r   )openai/gpt-5.4r   r   r"   r%   )zgoogle/gemini-3-flashr   r'   )zxai/grok-4.20-reasoningr   VERCEL_AI_GATEWAY_MODELS_ai_gateway_catalog_cachereturn	list[str]c                 B    ddl m} m}  |t          |                     S )a  Derive the openai-codex curated list from codex_models.py.

    Single source of truth: DEFAULT_CODEX_MODELS + forward-compat synthesis.
    This keeps the gateway /model picker in sync with the CLI `hermes model`
    flow without maintaining a separate static list.
    r   DEFAULT_CODEX_MODELS_add_forward_compat_models)hermes_cli.codex_modelsrA   rB   listr@   s     6/home/ubuntu/.hermes/hermes-agent/hermes_cli/models.py_codex_curated_modelsrF   d   s7     YXXXXXXX%%d+?&@&@AAA    )	zgrok-4.20-0309-reasoningzgrok-4.20-0309-non-reasoningzgrok-4.20-multi-agent-0309zgrok-4-1-fastzgrok-4-1-fast-non-reasoningzgrok-4-fastzgrok-4-fast-non-reasoningzgrok-4grok-code-fast-1_XAI_STATIC_FALLBACKc                    	 ddl m}   |             }t          |t                    r|                    d          nd}t          |t                    r|                    d          nd}t          |t                    r1|r/d |                                D             }|rt          |          S n# t          $ r Y nw xY wt          t                    S )a  Derive the xAI-direct curated list from models.dev disk cache.

    Reads $HERMES_HOME/models_dev_cache.json directly (no network) so this
    runs at import time without blocking. Falls back to ``_XAI_STATIC_FALLBACK``
    when the cache is empty or unreadable. Hermes refreshes the cache from
    https://models.dev/api.json on normal use, so this list self-heals as
    xAI renames models.

    Mirrors ``_codex_curated_models()``'s role for openai-codex.
    r   )_load_disk_cachexaiNmodelsc                <    g | ]}t          |t                    |S  )
isinstancestr).0mids     rE   
<listcomp>z'_xai_curated_models.<locals>.<listcomp>   s'    HHH3:c33G3GH3HHHrG   )
agent.models_devrK   rP   dictgetkeyssorted	ExceptionrD   rI   )rK   datarL   rM   idss        rE   _xai_curated_modelsr]      s    555555!!!+D$!7!7AdhhuoooT&0d&;&;E"""fd## 	# 	#HH&++--HHHC #c{{"    	 $%%%s   B-B1 1
B>=B>nous)r   r    r!   ztencent/hy3-previewr   r   r   r   r   r   r   r#   google/gemini-3-pro-previewr$   r&   r(   r)   r*   r+   r-   r.   r/   r0   r1   r2   zx-ai/grok-4.20-betar3   r4   r5   r6   openai)gpt-5.4gpt-5.4-mini
gpt-5-minigpt-5.3-codexgpt-5.2-codexgpt-4.1gpt-4ogpt-4o-miniopenai-codexcopilot-acpcopilot)ra   rb   rc   rd   re   rf   rg   rh   claude-sonnet-4.6claude-sonnet-4claude-sonnet-4.5claude-haiku-4.5gemini-3.1-pro-previewgemini-3-pro-previewgemini-3-flash-previewzgemini-2.5-prorH   gemini)rp   rq   rr   zgemini-3.1-flash-lite-previewzgoogle-gemini-cli)rp   rq   rr   zai)glm-5.1glm-5zglm-5v-turbozglm-5-turboglm-4.7zglm-4.5zglm-4.5-flashrL   nvidia)	r3   znvidia/nemotron-3-nano-30b-a3bz(nvidia/llama-3.3-nemotron-super-49b-v1.5zqwen/qwen3.5-397b-a17bzdeepseek-ai/deepseek-v3.2r   zminimaxai/minimax-m2.5z	z-ai/glm5zopenai/gpt-oss-120bzkimi-coding)	kimi-k2.6	kimi-k2.5zkimi-for-codingkimi-k2-thinkingzkimi-k2-thinking-turbokimi-k2-turbo-previewkimi-k2-0905-previewzkimi-coding-cn)ry   rz   r{   r|   r}   stepfunzstep-3.5-flashzstep-3.5-flash-2603moonshotminimax)MiniMax-M2.7MiniMax-M2.5zMiniMax-M2.1z
MiniMax-M2zminimax-oauthr   zMiniMax-M2.7-highspeed
minimax-cn)zclaude-opus-4-7claude-opus-4-6claude-sonnet-4-6zclaude-opus-4-5-20251101zclaude-sonnet-4-5-20250929zclaude-opus-4-20250514zclaude-sonnet-4-20250514zclaude-haiku-4-5-20251001)zdeepseek-v4-prozdeepseek-v4-flashzdeepseek-chatzdeepseek-reasoner)mimo-v2.5-pro	mimo-v2.5mimo-v2-promimo-v2-omnizmimo-v2-flashzhy3-preview)ztrinity-large-thinkingztrinity-large-previewztrinity-mini)zzai-org/GLM-5.1-FP8deepseek-ai/DeepSeek-V3.2moonshotai/Kimi-K2.5r(   r   r:   )#rz   zgpt-5.4-prora   rd   gpt-5.2re   zgpt-5.1zgpt-5.1-codexzgpt-5.1-codex-maxzgpt-5.1-codex-minigpt-5zgpt-5-codexz
gpt-5-nanor   zclaude-opus-4-5zclaude-opus-4-1r   claude-sonnet-4-5rm   claude-haiku-4-5zclaude-3-5-haikuzgemini-3.1-prozgemini-3-prozgemini-3-flashminimax-m2.7minimax-m2.5zminimax-m2.5-freezminimax-m2.1rv   rw   zglm-4.6r{   zkimi-k2zqwen3-coderz
big-pickle)ry   rz   ru   rv   r   r   r   r   r   r   qwen3.6-plusqwen3.5-plus)r   r   r:   r_   r$   )r   rz   r   zqwen3-coder-pluszqwen3-coder-nextrv   rw   r   )	r   zQwen/Qwen3.5-397B-A17BzQwen/Qwen3.5-35B-A3Br   zMiniMaxAI/MiniMax-M2.5zzai-org/GLM-5zXiaomiMiMo/MiMo-V2-Flashzmoonshotai/Kimi-K2-Thinkingzmoonshotai/Kimi-K2.6)
zus.anthropic.claude-sonnet-4-6zus.anthropic.claude-opus-4-6-v1z+us.anthropic.claude-haiku-4-5-20251001-v1:0z,us.anthropic.claude-sonnet-4-5-20250929-v1:0zus.amazon.nova-pro-v1:0zus.amazon.nova-lite-v1:0zus.amazon.nova-micro-v1:0zdeepseek.v3.2z)us.meta.llama4-maverick-17b-instruct-v1:0z&us.meta.llama4-scout-17b-instruct-v1:0)	anthropicdeepseekxiaomitencent-tokenhubarceegmiopencode-zenopencode-gokilocodealibabahuggingfacebedrockazure-foundryzdict[str, list[str]]_PROVIDER_MODELSc                    g | ]\  }}|S rO   rO   rR   rS   _s      rE   rT   rT     s    !M!M!M&#q#!M!M!MrG   
ai-gatewaymodel_idrQ   pricingdict[str, dict[str, str]]boolc                   |                     |           }|sdS 	 t          |                     dd                    dk    o&t          |                     dd                    dk    S # t          t          f$ r Y dS w xY w)zFReturn True if *model_id* has zero-cost prompt AND completion pricing.Fprompt1r   
completion)rW   float	TypeError
ValueError)r   r   ps      rE   _is_model_freer     s    HA uQUU8S))**a/XE!%%c:R:R4S4SWX4XXz"   uus   AA) )A>=A>r   access_tokenportal_base_urldict[str, Any]c                   |pd                     d          }| d}d|  dd}	 t          j                            ||          }t          j                            |d	          5 }t          j        |                                                                          cd
d
d
           S # 1 swxY w Y   d
S # t          $ r i cY S w xY w)a  Fetch the user's Nous Portal account/subscription info.

    Calls ``<portal>/api/oauth/account`` with the OAuth access token.

    Returns the parsed JSON dict on success, e.g.::

        {
            "subscription": {
                "plan": "Plus",
                "tier": 2,
                "monthly_charge": 20,
                "credits_remaining": 1686.60,
                ...
            },
            ...
        }

    Returns an empty dict on any failure (network, auth, parse).
    https://portal.nousresearch.com/z/api/oauth/accountBearer application/json)AuthorizationAcceptheaders   timeoutN)
rstripurllibrequestRequesturlopenjsonloadsreaddecoderZ   )r   r   baseurlr   reqresps          rE   fetch_nous_account_tierr     s%   ( @@HHMMD
%
%
%C1<11$ Gn$$S'$::^##C#33 	4t:diikk002233	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4   			s6   AB: (8B- B: -B11B: 4B15B: :C	C	account_infoc                    |                      d          }t          |t                    sdS |                     d          }|dS 	 t          |          dk    S # t          t
          f$ r Y dS w xY w)u   Return True if the account info indicates a free (unpaid) tier.

    Checks ``subscription.monthly_charge == 0``.  Returns False when
    the field is missing or unparseable (assumes paid — don't block users).
    subscriptionFmonthly_chargeNr   )rW   rP   rV   r   r   r   )r   subcharges      rE   is_nous_free_tierr     s     

>
*
*Cc4   uWW%&&F~uV}}!!z"   uus   A A/.A/	model_ids	free_tiertuple[list[str], list[str]]c                    |s| g fS |s| g fS g }g }| D ]=}t          ||          r|                    |           (|                    |           >||fS )a  Split Nous models into (selectable, unavailable) based on user tier.

    For paid-tier users: all models are selectable, none unavailable.

    For free-tier users: only free models are selectable; paid models
    are returned as unavailable (shown grayed out in the menu).
    )r   append)r   r   r   
selectableunavailablerS   s         rE   partition_nous_models_by_tierr     s      2 2JK $ $#w'' 	$c""""s####$$rG      int_FREE_TIER_CACHE_TTLztuple[bool, float] | None_free_tier_cachec                    t          j                    } t          t          \  }}| |z
  t          k     r|S 	 ddlm}m}  |d            |d          }|sd| fadS |                    dd	          }|                    d
d	          }|sd| fadS t          ||          }t          |          }	|	| fa|	S # t          $ r d| faY dS w xY w)u_  Check if the current Nous Portal user is on a free (unpaid) tier.

    Results are cached for ``_FREE_TIER_CACHE_TTL`` seconds to avoid
    hitting the Portal API on every call.  The cache is short-lived so
    that an account upgrade is reflected within a few minutes.

    Returns False (assume paid) on any error — never blocks paying users.
    Nr   )get_provider_auth_state resolve_nous_runtime_credentials<   )min_key_ttl_secondsr^   Fr   r   r   )time	monotonicr   r   hermes_cli.authr   r   rW   r   r   rZ   )
nowcached_result	cached_atr   r   stater   
portal_urlr   results
             rE   check_nous_free_tierr   5  s&    .

C##3 y?111  ]]]]]]]] 	)(R@@@@''// 	 %s|5yy44YY0"55
 	 %s|5.|ZHH"<00"C=   !3<uus   %B6 2B6 $B6 6CCz/api/nous/recommended-modelsiX  _NOUS_RECOMMENDED_CACHE_TTLz'dict[str, tuple[dict[str, Any], float]]_nous_recommended_cache      @Fforce_refreshr   r   r   c               l   | pd                     d          }t          j                    }t                              |          }|s||\  }}||z
  t
          k     r|S | t           }	 t          j        	                    |ddi          }	t          j        
                    |	|          5 }
t          j        |
                                                                          }ddd           n# 1 swxY w Y   t          |t                     si }n# t"          $ r i }Y nw xY w||ft          |<   |S )u  Fetch the Nous Portal's curated recommended-models payload.

    Hits ``<portal>/api/nous/recommended-models``. The endpoint is public —
    no auth is required. Results are cached per portal URL for
    ``_NOUS_RECOMMENDED_CACHE_TTL`` seconds; pass ``force_refresh=True`` to
    bypass the cache.

    Returns the parsed JSON dict on success, or ``{}`` on any failure
    (network, parse, non-2xx). Callers must treat missing/null fields as
    "no recommendation" and fall back to their own default.
    r   r   Nr   r   r   r   )r   r   r   r   rW   r   NOUS_RECOMMENDED_MODELS_PATHr   r   r   r   r   r   r   r   rP   rV   rZ   )r   r   r   r   r   cachedpayloadr   r   r   r   r[   s               rE   fetch_nous_recommended_modelsr   x  s   " @@HHMMD
.

C$((..F V/#?888N
1/
1
1C
n$$12 % 
 
 ^##C#99 	4T:diikk002233D	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4$%% 	D    &*3KD!Ks7   *AD .9C3'D 3C77D :C7;D D%$D%c                 .   	 ddl m} m}  |d          pi }t          |                    d          pd                                          }|r|                    d          S t          |                               d          S # t          $ r Y dS w xY w)zEBest-effort lookup of the Portal base URL the user is authed against.r   )DEFAULT_NOUS_PORTAL_URLr   r^   r   r   r   r   )r   r   r   rQ   rW   stripr   rZ   )r   r   r   portals       rE   _resolve_nous_portal_urlr     s    1	
 	
 	
 	
 	
 	
 	
 	
 ('//52UYY0117R88>>@@ 	&==%%%*++223777 1 1 10001s   A!B $!B 
BBentryr   Optional[str]c                    t          | t                    sdS |                     d          }t          |t                    r(|                                r|                                S dS )zGPull the ``modelName`` field from a recommended-model entry, else None.N	modelName)rP   rV   rW   rQ   r   )r  
model_names     rE   _extract_model_namer    sf    eT"" t;''J*c"" "z'7'7'9'9 "!!!4rG   )visionr   r   r   r  Optional[bool]c                   |pt                      }t          ||          }|sdS |"	 t                      }n# t          $ r d}Y nw xY w| rd\  }}nd\  }}|r|gn||g}|D ]*}	t	          |                    |	                    }
|
r|
c S +dS )u  Return the Portal's recommended model name for an auxiliary task.

    Picks the best field from the Portal's recommended-models payload:

    * ``vision=True``  → ``paidRecommendedVisionModel``  (paid tier) or
                         ``freeRecommendedVisionModel``  (free tier)
    * ``vision=False`` → ``paidRecommendedCompactionModel`` or
                         ``freeRecommendedCompactionModel``

    When ``free_tier`` is ``None`` (default) the user's tier is auto-detected
    via :func:`check_nous_free_tier`. Pass an explicit bool to bypass the
    detection — useful for tests or when the caller already knows the tier.

    For paid-tier users we prefer the paid recommendation but gracefully fall
    back to the free recommendation if the Portal returned ``null`` for the
    paid field (common during the staged rollout of new paid models).

    Returns ``None`` when every candidate is missing, null, or the fetch
    fails — callers should fall back to their own default (currently
    ``google/gemini-3-flash-preview``).
    r   NF)paidRecommendedVisionModelfreeRecommendedVisionModel)paidRecommendedCompactionModelfreeRecommendedCompactionModel)r   r   r   rZ   r  rW   )r  r   r   r   r   r   paid_keyfree_key
candidateskeynames              rE   get_nous_recommended_aux_modelr    s    8 8688D+DNNNG t	,..II 	 	 	 III	
  `W((_(
  )B(x.BJ  "7;;s#3#344 	KKK	4s   8 AAc                  .    e Zd ZU ded<   ded<   ded<   dS )ProviderEntryrQ   sluglabeltui_descN)__name__
__module____qualname____annotations__rO   rG   rE   r  r     s+         IIIJJJMMMMMrG   r  zNous Portalz(Nous Portal (Nous Research subscription)
openrouter
OpenRouterz%OpenRouter (100+ models, pay-per-use)lmstudioz	LM Studioz8LM Studio (local desktop app with built-in model server)r   	Anthropicu4   Anthropic (Claude models — API key or Claude Code)zOpenAI Codexr   zXiaomi MiMou:   Xiaomi MiMo (MiMo-V2.5 and V2 models — pro, omni, flash)r   zTencent TokenHubuJ   Tencent TokenHub (Hy3 Preview — direct API via tokenhub.tencentmaas.com)z
NVIDIA NIMu>   NVIDIA NIM (Nemotron models — build.nvidia.com or local NIM)z
qwen-oauthzQwen OAuth (Portal)z(Qwen OAuth (reuses local Qwen CLI login)zGitHub Copilotz3GitHub Copilot (uses GITHUB_TOKEN or gh auth token)zGitHub Copilot ACPz3GitHub Copilot ACP (spawns `copilot --acp --stdio`)r   zHugging Facez2Hugging Face Inference Providers (20+ open models)zGoogle AI Studiou6   Google AI Studio (Gemini models — native Gemini API)zGoogle Gemini (OAuth)zNGoogle Gemini via OAuth + Code Assist (free tier supported; no API key needed)r   DeepSeeku0   DeepSeek (DeepSeek-V3, R1, coder — direct API)xAIu    xAI (Grok models — direct API)z
Z.AI / GLMz Z.AI / GLM (Zhipu AI direct API)zKimi / Kimi Coding Planz.Kimi Coding Plan (api.kimi.com) & Moonshot APIzKimi / Moonshot (China)z.Kimi / Moonshot China (Moonshot CN direct API)zStepFun Step Planz9StepFun Step Plan (agent/coding models via Step Plan API)MiniMaxzMiniMax (global direct API)zMiniMax (OAuth)z9MiniMax via OAuth browser login (Coding Plan, minimax.io)zMiniMax (China)z#MiniMax China (domestic direct API)r   zAlibaba Cloud (DashScope)z8Alibaba Cloud / DashScope Coding (Qwen + multi-provider)ollama-cloudzOllama Cloudu6   Ollama Cloud (cloud-hosted open models — ollama.com)r   zArcee AIu(   Arcee AI (Trinity models — direct API)r   z	GMI Cloudz"GMI Cloud (multi-model direct API)r   z	Kilo CodezKilo Code (Kilo Gateway API)r   zOpenCode Zenz0OpenCode Zen (35+ curated models, pay-as-you-go)r   zOpenCode Goz1OpenCode Go (open models, $10/month subscription)r   zAWS Bedrocku>   AWS Bedrock (Claude, Nova, Llama, DeepSeek — IAM or API key)r   zAzure FoundryuU   Azure Foundry (OpenAI-style or Anthropic-style endpoint — your Azure AI deployment)zVercel AI Gatewayzlist[ProviderEntry]CANONICAL_PROVIDERSc                (    i | ]}|j         |j        S rO   )r  r  rR   r   s     rE   
<dictcomp>r(  *  s    AAAAFAGAAArG   zCustom endpointcustomglmzz-aizz.aizhipugithubzgithub-copilotzgithub-modelszgithub-modelzgithub-copilot-acpzcopilot-acp-agentgooglezgoogle-geminizgoogle-ai-studiokimizkimi-cnzmoonshot-cnstepzstepfun-coding-planzarcee-aiarceeaiz	gmi-cloudgmicloudzminimax-china
minimax_cnzminimax-portalzminimax-globalminimax_oauthclaudezclaude-codez	deep-seekopencodezengozopencode-go-sub	aigatewayvercelzvercel-ai-gatewaykiloz	kilo-codezkilo-gateway	dashscopealiyunqwenzalibaba-cloudzqwen-portalz
gemini-clizgemini-oauthhfzhugging-facezhuggingface-hubmimozxiaomi-mimotencenttokenhubztencent-cloudtencentmaasawszaws-bedrockzamazon-bedrockamazongrokzx-aizx.ainimz
nvidia-nimzbuild-nvidianemotron)r  z	lm-studio	lm_studioollamaollama_cloudproviderc                P    t                               | g           }|r|d         ndS )a  Return the default model for a provider, or empty string if unknown.

    Uses the first entry in _PROVIDER_MODELS as the default.  This is the
    model a user would be offered first in the ``hermes model`` picker.

    Used as a fallback when the user has configured a provider but never
    selected a model (e.g. ``hermes auth add openai-codex`` without
    ``hermes model``).
    r   r   )r   rW   )rK  rM   s     rE   get_default_model_for_providerrM  {  s,     !!(B//F&6!99B&rG   c                    t          | t                    sdS 	 t          |                     dd                    dk    o&t          |                     dd                    dk    S # t          t
          f$ r Y dS w xY w)z=Return True when both prompt and completion pricing are zero.Fr   0r   r   rP   rV   r   rW   r   r   r   s    rE   _openrouter_model_is_freerR    s    gt$$ uW[[3//00A5d%LZ]@^@^:_:_cd:ddz"   uu   AA' 'A<;A<itemc                    t          | t                    sdS |                     d          }t          |t                    sdS d|v S )u1  Return True when the model's ``supported_parameters`` advertise tool calling.

    hermes-agent is tool-calling-first — every provider path assumes the model
    can invoke tools. Models that don't advertise ``tools`` in their
    ``supported_parameters`` (e.g. image-only or completion-only models) cannot
    be driven by the agent loop and would fail at the first tool call.

    **Permissive when the field is missing.** Some OpenRouter-compatible gateways
    (Nous Portal, private mirrors, older catalog snapshots) don't populate
    ``supported_parameters`` at all. Treat that as "unknown capability → allow"
    so the picker doesn't silently empty for those users. Only hide models
    whose ``supported_parameters`` is an explicit list that omits ``tools``.

    Ported from Kilo-Org/kilocode#9068.
    Tsupported_parameterstools)rP   rV   rW   rD   )rT  paramss     rE    _openrouter_model_supports_toolsrY    sO      dD!! tXX,--Ffd## tfrG          @c                  t           |st          t                     S 	 ddlm}  |            }n# t          $ r d}Y nw xY w|rt          |          nt          t
                    }d |D             }	 t          j                            dddi          }t          j        	                    || 	          5 }t          j        |                                                                          }ddd           n# 1 swxY w Y   n&# t          $ r t          t           p|          cY S w xY w|                    d
g           }	t          |	t                    st          t           p|          S i }
|	D ]V}t          |t                     st#          |                    d          pd                                          }|sQ||
|<   Wg }|D ]g}|
                    |          }|t'          |          s*t)          |                    d                    rdnd}|                    ||f           h|st          t           p|          S |d         \  }}|df|d<   |a t          |          S )zYReturn the curated OpenRouter picker list, refreshed from the live catalog when possible.Nr   )get_curated_openrouter_modelsc                    g | ]\  }}|S rO   rO   r   s      rE   rT   z+fetch_openrouter_models.<locals>.<listcomp>      000VS!S000rG   z#https://openrouter.ai/api/v1/modelsr   r   r   r   r[   idr   r   r   r   )r9   rD   hermes_cli.model_catalogr\  rZ   r8   r   r   r   r   r   r   r   r   rW   rP   rV   rQ   r   rY  rR  r   )r   r   r\  remotefallbackpreferred_idsr   r   r   
live_items
live_by_idrT  rS   curatedpreferred_id	live_itemdescfirst_idr   s                      rE   fetch_openrouter_modelsrk    s    !,],-...JJJJJJ..00   %BtF|||40A+B+BH00x000M;n$$112 % 
 
 ^##C#99 	7Tj!3!3!5!566G	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 ; ; ;-9:::::; VR((Jj$'' ;-9:::,.J  $%% 	$((4..&B''--// 	
3%'G% 
- 
-NN<00	 0	:: 	29==3K3KLLTvvRTd+,,,, ;-9:::!*KHaM*GAJ '==sC   0 ??4AD	 89C=1D	 =DD	 DD	 	 D,+D,c                6    d t          |           D             S )z,Return just the OpenRouter model-id strings.c                    g | ]\  }}|S rO   rO   r   s      rE   rT   zmodel_ids.<locals>.<listcomp>      SSSFCCSSSrG   r   )rk  r   s    rE   r   r     "    SS5MRRRSSSSrG   c                     	 ddl m}   |             }n# t          $ r d}Y nw xY w|rt          |          S t          t                              dg                     S )a6  Return the curated Nous Portal model-id list.

    Prefers the remotely-hosted catalog manifest (published under
    ``website/static/api/model-catalog.json``); falls back to the in-repo
    snapshot in ``_PROVIDER_MODELS["nous"]`` when the manifest is
    unreachable. Always returns a list (never None).
    r   )get_curated_nous_modelsNr^   )r`  rq  rZ   rD   r   rW   )rq  ra  s     rE   get_curated_nous_model_idsrr    s    DDDDDD((**    F|| $$VR00111s    ""c                    t          | t                    sdS 	 t          |                     dd                    dk    o&t          |                     dd                    dk    S # t          t
          f$ r Y dS w xY w)zCReturn True if an AI Gateway model has $0 input AND output pricing.FinputrO  r   outputrP  rQ  s    rE   _ai_gateway_model_is_freerv    s    gt$$ uW[[#..//14_w{{8UX?Y?Y9Z9Z^_9__z"   uurS  c               >   t           |st          t                     S ddlm} t          t                    }d |D             }	 t
          j                            |                    d           dddi	          }t
          j        	                    || 
          5 }t          j        |                                                                          }ddd           n# 1 swxY w Y   n&# t          $ r t          t           p|          cY S w xY w|                    dg           }t!          |t                    st          t           p|          S i }	|D ]V}
t!          |
t"                    st%          |
                    d          pd                                          }|sQ|
|	|<   Wg }|D ]W}|	                    |          }|t)          |                    d                    rdnd}|                    ||f           X|st          t           p|          S t-          d |	                                D             d          r'fd|D             }|                    ddf           n|d         \  }}|df|d<   |a t          |          S )zYReturn the curated AI Gateway picker list, refreshed from the live catalog when possible.Nr   AI_GATEWAY_BASE_URLc                    g | ]\  }}|S rO   rO   r   s      rE   rT   z+fetch_ai_gateway_models.<locals>.<listcomp>  r^  rG   r   r
   r   r   r   r   r[   r_  r   r   r   c              3     K   | ]@\  }}|                     d           t          |                    d                    <|V  AdS )zmoonshotai/r   N)
startswithrv  rW   )rR   rS   rT  s      rE   	<genexpr>z*fetch_ai_gateway_models.<locals>.<genexpr>F  sj       	
 	
T~~m,,	
 *$((9*=*=>>		
	
 	
 	
 	
 	
 	
rG   c                *    g | ]\  }}|k    ||fS rO   rO   )rR   rS   ri  free_moonshots      rE   rT   z+fetch_ai_gateway_models.<locals>.<listcomp>O  s+    PPP933-;O;OC;;O;O;OrG   r   )r<   rD   hermes_constantsry  r;   r   r   r   r   r   r   r   r   r   rZ   rW   rP   rV   rQ   r   rv  r   nextitemsinsert)r   r   ry  rb  rc  r   r   r   rd  re  rT  rS   rf  rg  rh  ri  rj  r   r  s                     @rE   fetch_ai_gateway_modelsr    s1    !,],-...444444,--H00x000M;n$$"))#..77712 % 
 
 ^##C#99 	7Tj!3!3!5!566G	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 ; ; ;-9:::::; VR((Jj$'' ;-9:::,.J  $%% 	$((4..&B''--// 	
3%'G% - -NN<00	29==3K3KLLTvvRTd+,,,, ;-9::: 	
 	
'--//	
 	
 	
 	 M  /PPPPPPPq=-89999aj!.
 '==s7   AC1  9C%C1 %C))C1 ,C)-C1 1 DDc                6    d t          |           D             S )z,Return just the AI Gateway model-id strings.c                    g | ]\  }}|S rO   rO   r   s      rE   rT   z(ai_gateway_model_ids.<locals>.<listcomp>[  rn  rG   r   )r  r   s    rE   ai_gateway_model_idsr  Y  ro  rG   z$dict[str, dict[str, dict[str, str]]]_pricing_cacheper_token_strc                z    	 t          |           }n# t          t          f$ r Y dS w xY w|dk    rdS |dz  }d|dS )u  Convert a per-token price string to a human-friendly $/Mtok string.

    Always uses 2 decimal places so that prices align vertically when
    right-justified in a column (the decimal point stays in the same position).

    Examples:
        "0.000003"   → "$3.00"      (per million tokens)
        "0.00003"    → "$30.00"
        "0.00000015" → "$0.15"
        "0.0000001"  → "$0.10"
        "0.00018"    → "$180.00"
        "0"          → "free"
    ?r   r   i@B $z.2f)r   r   r   )r  valper_ms      rE   _format_price_per_mtokr  h  sb    M""z"   ss
axxv)OEu???s    ''      rM   pricing_mapcurrent_modelindentc                   | sg S g }d}| D ]\  }}||k    }|                     |          }	|	rtt          |	                     dd                    }
t          |	                     dd                    }|	                     dd          }|rt          |          nd}|rd}nd\  }
}}|                    ||
|||f           t          d |D                       d	z   }t          t          d
 |D             d          t          d |D             d          d          }|r)t          t          d |D             d          d          nd}g }|rb|                    | dd| ddd| ddd| ddd| d	           |                    | d|z   dd|z   dd|z   dd|z              nT|                    | dd| ddd| ddd| d           |                    | d|z   dd|z   dd|z              |D ]r\  }}
}}}|rdnd}|r5|                    | |d| d|
d| d|d| d|d| | 	           E|                    | |d| d|
d| d|d| |            s|S )zBuild a column-aligned model+pricing table for terminal display.

    Returns a list of pre-formatted lines ready to print.
    *models* is ``[(model_id, description), ...]``.
    Fr   r   r   input_cache_readT)r   r   r   c              3  @   K   | ]}t          |d                    V  dS )r   NlenrR   rs     rE   r}  z-format_model_pricing_table.<locals>.<genexpr>  s,      ++3qt99++++++rG      c              3  P   K   | ]!}|d          
t          |d                    V  "dS )   Nr  r  s     rE   r}  z-format_model_pricing_table.<locals>.<genexpr>  5      --1!-S1YY------rG      )defaultc              3  P   K   | ]!}|d          
t          |d                    V  "dS )r  Nr  r  s     rE   r}  z-format_model_pricing_table.<locals>.<genexpr>  r  rG      c              3  P   K   | ]!}|d          
t          |d                    V  "dS )r  Nr  r  s     rE   r}  z-format_model_pricing_table.<locals>.<genexpr>  r  rG      r   Model< In>z  OutCachez  /Mtok-u     ← current)rW   r  r   max)rM   r  r  r  rows	has_cacherS   _descis_curr   inpout
cache_readcachename_col	price_col	cache_collinesmarkers                      rE   format_model_pricing_tabler    s     	 35DI 4 4
U%OOC   	)(x)<)<==C(|R)@)@AAC1266J:DL*:666"E ! 	(OCeS#sE623333++d+++++a/H-----q999-----q999	 I 
-----q999	     E  W~~(~~~~d~Y~~~~5~S\~~~~ah~kt~~~~~hhhhyhhC)OhhWZ]fWfhhiiiiff(ffffdfYffff5fS\fffffgggUhUUyUUC)OUUVVV(, f f$S#uf$*2 	fLLFzCz(zzzzczIzzzz#zPYzzzz^czfozzzrxzz{{{{LLFdCd(ddddcdIdddd#dPYddd\bddeeeeLrG   https://openrouter.ai/apiapi_key
str | Nonebase_urlc               4   |pd                     d          }|s|t          v rt          |         S |                     d          dz   }dt          d}| rd|  |d<   	 t          j                            ||          }t          j                            ||	          5 }t          j        |	                                
                                          }	d
d
d
           n# 1 swxY w Y   n# t          $ r i t          |<   i cY S w xY wi }
|	                    dg           D ]}|                    d          }|                    d          }|rt          |t                    rt          |                    dd                    t          |                    dd                    d}|                    d          rt          |d                   |d<   |                    d          rt          |d                   |d<   ||
|<   |
t          |<   |
S )zFetch ``/v1/models`` and return ``{model_id: {prompt, completion}}`` pricing.

    Results are cached per *base_url* so repeated calls are free.
    Works with any OpenRouter-compatible endpoint (OpenRouter, Nous Portal).
    r   r   z
/v1/modelsr   )r   
User-Agentr   r   r   r   Nr[   r_  r   r   r   r   r   r  input_cache_write)r   r  _HERMES_USER_AGENTr   r   r   r   r   r   r   r   rZ   rW   rP   rV   rQ   )r  r  r   r   	cache_keyr   r   r   r   r   r   rT  rS   r   r  s                  rE   fetch_models_with_pricingr    sp    R'',,I )Y.88i((


3

,
.C$( G  7#6W#6#6 n$$S'$::^##C#99 	7Tj!3!3!5!566G	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7   $&y!			 )+FFB''    hhtnn((9%% 		 :gt,, 		 gkk(B7788!'++lB"?"?@@% %E {{-.. M,/8J0K,L,L(){{.// O-09L1M-N-N)*F3K &N9Ms7   AC0 9C$C0 $C((C0 +C(,C0 0D	D	c                   ddl m} |                    d          }|s|t          v rt          |         S 	 t          j                            | dddi          }t          j                            ||           5 }t          j	        |
                                                                          }d	d	d	           n# 1 swxY w Y   n# t          $ r i t          |<   i cY S w xY wi }|                    d
g           D ]}t          |t                    s|                    d          }	|                    d          }
|	rt          |
t                    s[t!          |
                    dd                    t!          |
                    dd                    d}|
                    d          rt!          |
d                   |d<   |
                    d          rt!          |
d                   |d<   |||	<   |t          |<   |S )zFetch Vercel AI Gateway /v1/models and return hermes-shaped pricing.

    Vercel uses ``input`` / ``output`` field names; hermes's picker expects
    ``prompt`` / ``completion``. This translates. Cache read/write field names
    already match.
    r   rx  r   r
   r   r   r   r   Nr[   r_  r   rt  r   ru  r  r  r  )r  ry  r   r  r   r   r   r   r   r   r   r   rZ   rW   rP   rV   rQ   )r   r   ry  r  r   r   r   r   rT  rS   r   r  s               rE   fetch_ai_gateway_pricingr    sj    544444#**3//I )Y.88i((	n$$!!!12 % 
 
 ^##C#99 	7Tj!3!3!5!566G	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7   $&y!			 )+FFB''  $%% 	hhtnn((9%% 	
7D11 	'++gr2233gkk(B7788!
 !
 ;;)** 	I(+G4F,G(H(HE$%;;*++ 	K),W5H-I)J)JE%&s &N9Ms6   AC <9C5C CC C	C C&%C&c                 P    t          j        dd                                          S )z1Best-effort OpenRouter API key for pricing fetch.OPENROUTER_API_KEYr   )osgetenvr   rO   rG   rE   _resolve_openrouter_api_keyr  #  s!    9)2..44666rG   tuple[str, str]c                     	 ddl m}   |             }|r,|                    dd          |                    dd          fS n# t          $ r Y nw xY wdS )zIReturn ``(api_key, base_url)`` for Nous Portal pricing, or empty strings.r   )r   r  r   r  )r   r   )r   r   rW   rZ   )r   credss     rE   !_resolve_nous_pricing_credentialsr  (  s    DDDDDD0022 	IIIi,,eii
B.G.GHH	I   8s   =A 
AAc               V   t          |           }|dk    rt          t                      d|          S |dk    rt          |          S |dk    rYt	                      \  }}|rF|                    d          }|                    d          r
|d	d
         }t          |||          S i S )zQReturn live pricing for providers that support it (openrouter, nous, ai-gateway).r  r  )r  r  r   r   r   r^   r   /v1N)normalize_providerr  r  r  r  r   endswith)rK  r   
normalizedr  r  strippeds         rE   get_pricing_for_providerr  4  s    #H--J\!!(/110'
 
 
 	

 \!!'mDDDDV=?? 
	  s++H  '' )#CRC=,!+   
 IrG   set[str]_KNOWN_PROVIDER_NAMESlist[dict[str, str]]c                    d t           D             dgz   } i }t                                          D ].\  }}|                    |g                               |           /g }| D ]	}t
                              ||          }|                    |g           }d}	 ddlm}	m	}
 |dk    r2t                      pd}t          |                                          }ng|dk    r |
t          j        dd                    }nB |	|          }t          |                    d	          p|                    d
                    }n# t          $ r Y nw xY w|                    ||||d           |S )aR  Return info about all providers the user could use with ``provider:model``.

    Each dict has ``id``, ``label``, and ``aliases``.
    Checks which providers have valid credentials configured.

    Derives the provider list from :data:`CANONICAL_PROVIDERS` (single
    source of truth shared with ``hermes model``, ``/model``, etc.).
    c                    g | ]	}|j         
S rO   )r  r'  s     rE   rT   z,list_available_providers.<locals>.<listcomp>a  s    :::af:::rG   r)  Fr   )get_auth_statushas_usable_secretr   r  r  	logged_in
configured)r_  r  aliasesauthenticated)r%  _PROVIDER_ALIASESr  
setdefaultr   _PROVIDER_LABELSrW   r   r  r  _get_custom_base_urlr   r   r  r  rZ   )provider_orderaliases_foralias	canonicalr   pidr  
alias_list	has_credsr  r  custom_base_urlstatuss                rE   list_available_providersr  W  s    ;:&9:::hZGN )+K-3355 < <yy"--44U;;;;F   $$S#.. __S"--
		JJJJJJJJh"6"8"8">B !6!6!8!899		$$--bi8Lb.Q.QRR		(-- K!8!8!TFJJ|<T<TUU	 	 	 	D	!&	
 
 	 	 	 	 Ms   B'E
EErawcurrent_providerc                   |                                  }|                    d          }|dk    r|d|                                                                          }||dz   d                                          }|r|r|t          v rv|dk    r_d|v r[|                    d          }|d|                                          }||dz   d                                          }|r	|rd| |fS t	          |          |fS ||fS )uh  Parse ``/model`` input into ``(provider, model)``.

    Supports ``provider:model`` syntax to switch providers at runtime::

        openrouter:anthropic/claude-sonnet-4.5  →  ("openrouter", "anthropic/claude-sonnet-4.5")
        nous:hermes-3                           →  ("nous", "hermes-3")
        anthropic/claude-sonnet-4.5             →  (current_provider, "anthropic/claude-sonnet-4.5")
        gpt-5.4                                 →  (current_provider, "gpt-5.4")

    The colon is only treated as a provider delimiter if the left side is a
    recognized provider name or alias.  This avoids misinterpreting model names
    that happen to contain colons (e.g. ``anthropic/claude-3.5-sonnet:beta``).

    Returns ``(provider, model)`` where *provider* is either the explicit
    provider from the input or *current_provider* if none was specified.
    :r   Nr  r)  zcustom:)r   findlowerr  r  )	r  r  r  colonprovider_part
model_partsecond_coloncustom_nameactual_models	            rE   parse_model_inputr    s0   " yy{{HMM#Eqyy %(..006688eaijj)//11
 
	CZ 
	CM=R,R,R ((SJ->->)s33(,7==??),*:*;*;<BBDD C< C3k33\BB&}55zBBh''rG   c                 
   	 ddl m}   |             }|                    di           }t          |t                    r5t          |                    dd                                                    S n# t          $ r Y nw xY wdS )z2Get the custom endpoint base_url from config.yaml.r   )load_configmodelr  r   )hermes_cli.configr  rW   rP   rV   rQ   r   rZ   )r  config	model_cfgs      rE   r  r    s    111111JJw++	i&& 	>y}}Z4455;;===	>   2s   A/A3 3
B ?B c                   t          |           }|dk    rt          |          S t          |          }|rd |D             S t                              |g           }d |D             S )zReturn ``(model_id, description)`` tuples for a provider's model list.

    Tries to fetch the live model list from the provider's API first,
    falling back to the static ``_PROVIDER_MODELS`` catalog if the API
    is unreachable.
    r  r   c                    g | ]}|d fS r   rO   rR   ms     rE   rT   z/curated_models_for_provider.<locals>.<listcomp>  s    &&&AB&&&rG   c                    g | ]}|d fS r  rO   r	  s     rE   rT   z/curated_models_for_provider.<locals>.<listcomp>  s    $$$QG$$$rG   )r  rk  provider_model_idsr   rW   )rK  r   r  liverM   s        rE   curated_models_for_providerr    s     $H--J\!!&]CCCC j))D '&&&&&& !!*b11F$$V$$$$rG   c                    | pd                                                                 }t          |           }d ||fD             S )Nr   c                    h | ]}||S rO   rO   )rR   ks     rE   	<setcomp>z!_provider_keys.<locals>.<setcomp>  s    ...!A.A...rG   )r   r  r  )rK  r  r  s      rE   _provider_keysr    sI    >r
 
 
"
"
(
(
*
*C#H--J..Z(....rG   
name_lower	providersc                :     t           fd|D                       S )Nc              3     K   | ]:}t                               |g           D ]}|                                k    V  ;d S N)r   rW   r  )rR   rK  r  r  s      rE   r}  z-_model_in_provider_catalog.<locals>.<genexpr>  sk        %))(B77   	ekkmm#      rG   )any)r  r  s   ` rE   _model_in_provider_catalogr    s;        !     rG   >   r^   rk   r   r  r   current_keysOptional[tuple[str, str]]c                `   	 ddl m} n# t          $ r Y dS w xY w|                    |           }|dS |j        |j        d	fd}|D ]} ||          x}r||fc S t          D ]#}||v s	|t          v r ||          x}r||fc S $t          D ]}||v r ||          x}r||fc S dS )
zDResolve short aliases (e.g. sonnet/opus) using static catalogs only.r   )MODEL_ALIASESNrK  rQ   r=   r  c                    t                               | g           }|sd S | t          v r d n                                }|D ]-}|                                                    |          r|c S .d S )Nr   )r   rW   _AGGREGATOR_PROVIDERSr  r|  )rK  rM   prefixr  familyvendors       rE   _matchz+_resolve_static_model_alias.<locals>._match  s    !%%h33 	4 000      
%''	 	
  	 	E{{}}''// trG   )rK  rQ   r=   r  )hermes_cli.model_switchr  rZ   rW   r#  r"  r   r   )	r  r  r  identityr$  rK  matchedr"  r#  s	          @@rE   _resolve_static_model_aliasr(    sm   
9999999   tt   ,,Ht_F_F       ! % %fX&&&7 	%W$$$$	% % % %|##x3H'H'HfX&&&7 	%W$$$$	% * % %|##FF84D4D)D#W$$$$4s    
r  c                  	 | pd                                 }|sdS |                                	t          |          }t          	|          }|r|S t                              		          }|dvr4t                              |g           }|t          v r|r||vr
||d         fS t          	|          rdS t          	                                D ]4\  }}||v s	|t          v rt          	fd|D                       r||fc S 5dS )a  Auto-detect a provider from static catalogs only.

    Returns ``(provider_id, model_name)``. The model name may be remapped
    when a static alias or bare provider name resolves to a catalog default.
    Returns ``None`` when no confident match is found.
    r   N>   r)  r  r   c              3  H   K   | ]}|                                 k    V  d S r  r  )rR   r
  r  s     rE   r}  z3detect_static_provider_for_model.<locals>.<genexpr>=  s0      771zQWWYY&777777rG   )r   r  r  r(  r  rW   r   r  r  r  r   r  )
r  r  r  r  alias_matchresolved_providerdefault_modelsr  rM   r  s
            @rE    detect_static_provider_for_modelr/    s]    "##%%D tJ!"233L-j,GGK  *--j*EE 888)--.?DD!111 2!55%~a'899 "*l;; t (--//  V,#)>">">777777777 	;	 4rG   c                   | pd                                 }|sdS t          ||          }|r|S t          |                                t	          |                    rdS t          |          }|r|dk    rd|fS ||k    rd|fS dS dS )u  Auto-detect the best provider for a model name.

    Returns ``(provider_id, model_name)`` — the model name may be remapped
    (e.g. bare ``deepseek-chat`` → ``deepseek/deepseek-chat`` for OpenRouter).
    Returns ``None`` when no confident match is found.

    Priority:
    0. Bare provider name → switch to that provider's default model
    1. Direct provider static catalog match
    2. OpenRouter catalog match
    r   Nr  )r   r/  r  r  r  _find_openrouter_slug)r  r  r  static_matchor_slugs        rE   detect_provider_for_modelr4  C  s     "##%%D t3D:JKKL !$**,,?O0P0PQQ t $D))G |++ '**d?? '**t4rG   c                H   |                                                                  }|sdS t                      D ]}||                                k    r|c S t                      D ];}d|v r5|                    dd          \  }}||                                k    r|c S <dS )u  Find the full OpenRouter model slug for a bare or partial model name.

    Handles:
    - Exact match: ``anthropic/claude-opus-4.6`` → as-is
    - Bare name: ``deepseek-chat`` → ``deepseek/deepseek-chat``
    - Bare name: ``claude-opus-4.6`` → ``anthropic/claude-opus-4.6``
    Nr   r  )r   r  r   split)r  r  rS   r   r  s        rE   r1  r1  j  s     !!##))++J t {{  $$JJJ % {{  #::IIc1--MAzZ--////


4rG   c                    | pd                                                                 }t                              ||          S )u   Normalize provider aliases to Hermes' canonical provider ids.

    Note: ``"auto"`` passes through unchanged — use
    ``hermes_cli.auth.resolve_provider()`` to resolve it to a concrete
    provider based on credentials and environment.
    r  )r   r  r  rW   )rK  r  s     rE   r  r    s<     *l113399;;J  Z888rG   c                    | pd                                 }|                                }|dk    rdS t          |          }t                              ||pd          S )z9Return a human-friendly label for a provider id or alias.r  autoAutor  )r   r  r  r  rW   )rK  originalr  s      rE   provider_labelr<    s_    (L//11H!!JVv#J//J
H,DEEErG   )gpt-o1o3o4ztuple[str, ...]_OPENAI_FAST_MODE_PREFIXESc                    t          t          | pd                    }|                    d          d         sdS dv rdS t          fdt          D                       S )zPReturn True if the model is an OpenAI flagship eligible for Priority Processing.r   r  r   Fcodexc              3  B   K   | ]}                     |          V  d S r  )r|  )rR   r!  r   s     rE   r}  z(_is_openai_fast_model.<locals>.<genexpr>  s/      PP6tv&&PPPPPPrG   )_strip_vendor_prefixrQ   r6  r  rA  r   r  r   s     @rE   _is_openai_fast_modelrG    sq    
s8>r22
3
3C99S>>!D u $uPPPP5OPPPPPPrG   c                    t          | pd                                                                          }d|v r|                    dd          d         }|S )z]Strip vendor/ prefix from a model ID (e.g. 'anthropic/claude-opus-4-6' -> 'claude-opus-4-6').r   r   r  )rQ   r   r  r6  )r   r  s     rE   rE  rE    sQ    
hn"


#
#
%
%
+
+
-
-C
czziiQ"JrG   c                >    t          |           pt          |           S )zDReturn whether Hermes should expose the /fast toggle for this model.)_is_anthropic_fast_modelrG  r   s    rE   model_supports_fast_moderL    s    #H--P1Fx1P1PPrG   c                    t          t          | pd                    }|                    d          d         }|                    d          S )zLReturn True if the model is a Claude model eligible for Anthropic Fast Mode.r   r  r   claude-)rE  rQ   r6  r|  rF  s      rE   rJ  rJ    sA    
s8>r22
3
3C99S>>!D??9%%%rG   dict[str, Any] | Nonec                R    t          |           sdS t          |           rddiS ddiS )u  Return request_overrides for fast/priority mode, or None if unsupported.

    Returns provider-appropriate overrides:
    - OpenAI models: ``{"service_tier": "priority"}`` (Priority Processing)
    - Anthropic models: ``{"speed": "fast"}`` (Anthropic Fast Mode beta)

    The overrides are injected into the API request kwargs by
    ``_build_api_kwargs`` in run_agent.py — each API path handles its own
    keys (service_tier for OpenAI/Codex, speed for Anthropic Messages).
    Nspeedfastservice_tierpriority)rL  rJ  rK  s    rE   resolve_fast_mode_overridesrU    s?     $H-- t)) !  J''rG   c                 (   	 ddl m}   | d          }t          |                    d          pd                                          }|r|S n# t
          $ r Y nw xY w	 ddl m} ddlm}m	}  |d          D ]}t          |t                    st          |                    d          pd                                          }|sQ ||          \  }}	|sb	  ||          \  }
}n# t
          $ r Y ~w xY w|
r|
c S n# t
          $ r Y nw xY wdS )	u3  Best-effort GitHub token for fetching the Copilot model catalog.

    Resolution order:
      1. ``resolve_api_key_provider_credentials("copilot")`` — env vars
         (``COPILOT_GITHUB_TOKEN`` / ``GH_TOKEN`` / ``GITHUB_TOKEN``) plus
         the ``gh auth token`` CLI fallback.
      2. ``read_credential_pool("copilot")`` — a token (typically a
         ``gho_*`` from device-code login, or a fine-grained PAT) stored in
         ``auth.json`` under ``credential_pool.copilot[]``. The pool is
         populated by ``hermes auth add copilot`` and by ``_seed_from_env``
         when the env var is set in ``~/.hermes/.env``.

    Without (2), users whose only Copilot credential is in the pool see
    the ``/model`` picker fall back to a stale hardcoded list because the
    live catalog fetch silently 401s. To avoid wedging on a malformed pool
    entry, each candidate is exchanged via ``exchange_copilot_token`` —
    only entries that actually exchange successfully are returned, so a
    later valid entry is reachable when an earlier one is unsupported.
    r   $resolve_api_key_provider_credentialsrk   r  r   )read_credential_pool)exchange_copilot_tokenvalidate_copilot_tokenr   )r   rX  rQ   rW   r   rZ   rY  hermes_cli.copilot_authrZ  r[  rP   rV   )rX  r  r  rY  rZ  r[  r  r  validr   	api_token_expires_ats               rE    _resolve_copilot_catalog_api_keyr`    s   (HHHHHH44Y??eii	**0b117799 	N	   888888	
 	
 	
 	
 	
 	
 	
 	

 *))44 	! 	!EeT** eii//5266<<>>C --c22HE1 )?)?)D)D&	;;    !    !	!     2sO   A
A 
AAA;D C*)D *
C74D 6C77D  D 
DD>   rt   groqcoherers   r-  rx   mistralr   r   	fireworks
perplexity
togetherair   r   r   zfrozenset[str]_MODELS_DEV_PREFERREDrf  c                   	 ddl m}  ||           }n# t          $ r g }Y nw xY w|st          |          S t	                      }g }|D ]R}t          |                                          }||v r(|                    |           |                    |           S|D ]R}t          |                                          }||v r(|                    |           |                    |           S|S )u  Merge curated list with fresh models.dev entries for a preferred provider.

    Returns models.dev entries first (in models.dev order), then any
    curated-only entries appended. Preserves case for curated fallbacks
    (e.g. ``MiniMax-M2.7``) while trusting models.dev for newer variants.

    If models.dev is unreachable or returns nothing, the curated list is
    returned unchanged — this is the offline/CI fallback path.
    r   list_agentic_models)	rU   rj  rZ   rD   setrQ   r  addr   )rK  rf  rj  mdev
seen_lowermergedrS   r  s           rE   _merge_with_models_devrp  B  s,   888888""8,,     G}} 55JF  #hhnn*sc  #hhnn*scMs    ##c                  t          |           }|dk    rt          |          S |dk    rOddlm} d}	 ddlm}  |d	          }|                    d
          }n# t          $ r d}Y nw xY w ||          S |dv r_	 t          t                                }|r|S n# t          $ r Y nw xY w|dk    r(t          t                              dg                     S |dk    r_	 ddlm}m}	  |	            }|r9 ||                    d
d          |                    dd                    }|r|S n# t          $ r Y nw xY w|dk    r	 ddlm}
  |
d          }t          |                    d
          pd                                          }t          |                    d          pd                                          }|r|rt#          ||          }|r|S n# t          $ r Y nw xY w|dk    rt%                      }|r|S |dk    rt'                      }|r|S |dk    rt)          |          }|r|S |dk    rt+          j        dd                                          }|rdt+          j        dd                                                              d          }|pd}	 t#          ||          }|r|S n# t          $ r Y nw xY w|dk    r	 ddlm}
  |
d          }t          |                    d
          pd                                          }t          |                    d          pd                                          }|r|rt#          ||          }|r|S n# t          $ r Y nw xY w|dk    rct1                      }|rSt+          j        d d          p)t+          j        dd          pt+          j        d!d          }t#          ||          }|r|S |d"k    r&	 dd#lm}  |            }||S n# t          $ r Y nw xY wt          t                              |g                     }|t6          v rt9          ||          S |S )$a  Return the best known model catalog for a provider.

    Tries live API endpoints for providers that support them (Codex, Nous),
    falling back to static lists. For providers in ``_MODELS_DEV_PREFERRED``
    (opencode-go/zen, xiaomi, deepseek, smaller inference providers, etc.),
    models.dev entries are merged on top of curated so new models released
    on the platform appear in ``/model`` without a Hermes release.
    r  r   ri   r   )get_codex_model_idsN)!resolve_codex_runtime_credentialsT)refresh_if_expiringr  )r   >   rk   rj   rj   rk   r^   )fetch_nous_modelsr   r   r  )r  inference_base_urlr~   rW  r   r   r$  r`   OPENAI_API_KEYOPENAI_BASE_URLr   zhttps://api.openai.com/v1r   r)  CUSTOM_API_KEYr  r   )bedrock_model_ids_or_none)r  r   rC   rr  r   rs  rW   rZ   _fetch_github_modelsr`  rD   r   ru  r   rX  rQ   r   fetch_api_models_fetch_anthropic_models_fetch_ai_gateway_modelsfetch_ollama_cloud_modelsr  r  r   r  agent.bedrock_adapterrz  rg  rp  )rK  r   r  rr  r   rs  r  r  ru  r   rX  r  r  base_rawr   rz  r\   curated_statics                     rE   r  r  g  s    $H--J\!!}5555^##?????? 	 IIIIII55$OOOE 99Y//LL 	  	  	 LLL	 ""====///	'(H(J(JKKD  	 	 	D	&&(,,Y;;<<<V	[[[[[[[[4466E  ((9b1I1I^c^g^ghrtv^w^wxxx  K 	 	 	D	Y	LLLLLL88CCE%))I..4"55;;==G599Z006B77==??H  8  '::  K 	 	 	D	[  &(( 	K\!!')) 	K^##(}EEE 	KX),b117799 	y!2B77==??FFsKKH::D'66  K    U	LLLLLL88??E%))I..4"55;;==G599Z006B77==??H  8  '::  K 	 	 	D	X')) 		 	*B// 79-r22791266 
 $GX66D 
 Y	GGGGGG++--C
  	 	 	D	*..z2>>??N***%j.AAAs   'A A,+A, B   
B-,B-%AD3 3
E ?E 
BG   
G-,G-(J= =
K
	K
BM* *
M76M7*O? ?
PPOptional[list[str]]c                    	 ddl m}m} n# t          $ r Y dS w xY w |            }|sdS ddi} ||          }|r.d| |d<   ddl m}m}m d	                    ||z             |d
<   n||d<   d fd}	 	  ||          }	n# t          j	        j
        $ r}
|r|
j        dk    r	 |
                                                    d                                          }n# t          $ r d}Y nw xY wd|v rDd|v r@d	                    fd|D             t!          |          z             |d
<    ||          }	n  Y d}
~
nd}
~
ww xY wd |	                    dg           D             }t%          |d           S # t          $ r=}ddl}|                    t*                                        d|           Y d}~dS d}~ww xY w)zFetch available models from the Anthropic /v1/models endpoint.

    Uses resolve_anthropic_token() to find credentials (env vars or
    Claude Code auto-discovery).  Returns sorted model IDs or None.
    r   )resolve_anthropic_token_is_oauth_tokenNanthropic-version
2023-06-01r   r   )_COMMON_BETAS_OAUTH_ONLY_BETAS_CONTEXT_1M_BETA,zanthropic-beta	x-api-keyhdict[str, str]c                ,   t           j                            d|           }t           j                            |          5 }t	          j        |                                                                          cd d d            S # 1 swxY w Y   d S )Nz#https://api.anthropic.com/v1/modelsr   r   )r   r   r   r   r   r   r   r   )r  r   r   r   s      rE   _do_requestz,_fetch_anthropic_models.<locals>._do_request  s    n$$1 % 
 
 ^##C#99 	4T:diikk002233	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4s   8B		BBi  ignore)errorsr   zlong context betaznot yet availablec                     g | ]
}|k    |S rO   rO   )rR   br  s     rE   rT   z+_fetch_anthropic_models.<locals>.<listcomp>  s$    KKKqQ:J5J5J5J5J5JrG   c                H    g | ]}|                     d           |d           S r_  rW   r	  s     rE   rT   z+_fetch_anthropic_models.<locals>.<listcomp>   s+    GGGa155;;G!D'GGGrG   r[   c                    d| vd| vd| v| fS )NopussonnethaikurO   )r
  s    rE   <lambda>z)_fetch_anthropic_models.<locals>.<lambda>"  s#    !OA1	-
 rG   )r  z$Failed to fetch Anthropic models: %s)r  r  )agent.anthropic_adapterr  r  ImportErrorr  r  r  joinr   error	HTTPErrorcoder   r   r  rZ   rD   rW   rY   logging	getLoggerr  debug)r   r  r  tokenr   is_oauthr  r  r  r[   http_err	body_textrM   er  r  s   `              @rE   r}  r}    s   TTTTTTTTT   tt $#%%E t2LAGu%%H %#4U#4#4 ^^^^^^^^^^$'HH]=N-N$O$O !!$4 4 4 4 4 4%	;w''DD|% 	 	 	 MS((# ( 6 6h 6 G G M M O OII  # # # "III#&)338Ky8X8X03KKKKMKKK01121 1G,- ';w//DD	 DDDD%	. HG488FB#7#7GGGf #
 #
    	    (##))*PRSTTTtttttsm    
8B E< EE&:C! E!C0-E/C00AE=E< E4E< <
G2F>>Gr   list[dict[str, Any]]c                    t          | t                    rd | D             S t          | t                    r7|                     dg           }t          |t                    rd |D             S g S )Nc                <    g | ]}t          |t                    |S rO   rP   rV   rR   rT  s     rE   rT   z"_payload_items.<locals>.<listcomp>0  s'    CCCJtT,B,BCCCCrG   r[   c                <    g | ]}t          |t                    |S rO   r  r  s     rE   rT   z"_payload_items.<locals>.<listcomp>4  s'    DDDTZd-C-CDDDDDrG   )rP   rD   rV   rW   )r   r[   s     rE   _payload_itemsr  .  s{    '4   DCCCCCC'4   E{{62&&dD!! 	EDDTDDDDIrG   r  c                 `    	 ddl m}   | d          S # t          $ r t          ddddcY S w xY w)	zStandard headers for Copilot API requests.

    Includes Openai-Intent and x-initiator headers that opencode and the
    Copilot CLI send on every request.
    r   copilot_request_headersT)is_agent_turnzHermesAgent/1.0zconversation-editsagent)zEditor-Versionr  zOpenai-Intentzx-initiator)r\  r  r  COPILOT_EDITOR_VERSIONr  s    rE   copilot_default_headersr  8  sm    	
CCCCCC&&T:::: 
 
 
4+1"	
 
 	
 	
 	

s    --c                F   t          |                     d          pd                                          }|sdS |                     d          du rdS |                     d          }t          |t                    rRt          |                    d          pd                                                                          }|r|dk    rdS |                     d          }t          |t                    r'd	 |D             }|r|                    h d
          sdS dS )Nr_  r   Fmodel_picker_enabledcapabilitiestypechatsupported_endpointsc                    h | ]D}t          |                                          #t          |                                          ES rO   rQ   r   rR   endpoints     rE   r  z6_copilot_catalog_item_is_text_model.<locals>.<setcomp>Z  sR      
  
  
8}}""$$ 
MM!! 
  
  
rG   >   
/responses/v1/messages/chat/completionsT)rQ   rW   r   rP   rV   r  rD   intersection)rT  r   r  
model_typer  normalized_endpointss         rE   #_copilot_catalog_item_is_text_modelr  J  sB   488D>>'R((..00H uxx&''500u88N++L,%% ))&117R88>>@@FFHH
 	*..5((#899%t,, 	 
  
/ 
  
  

   	(<(I(I???)
 )
 	 54rG   Optional[list[dict[str, Any]]]c                `   g }| r*|                     i t                      dd|  i           |                     t                                 |D ]Z}t          j                            t
          |          }	 t          j                            ||          5 }t          j        |	                                
                                          }t          |          }g }t                      }	|D ]y}
t          |
          st          |
                    d          pd                                          }|r||	v rO|	                    |           |                     |
           z|r|cddd           c S 	 ddd           n# 1 swxY w Y   K# t$          $ r Y Xw xY wdS )z=Fetch the live GitHub Copilot model catalog for this account.r   r   r   r   r_  r   N)r   r  r   r   r   COPILOT_MODELS_URLr   r   r   r   r   r  rk  r  rQ   rW   r   rl  rZ   )r  r   attemptsr   r   r   r[   r  rM   seen_idsrT  r   s               rE   fetch_github_model_catalogr  g  s7    &(H  
%''
0w00
 
 	 	 	 OO+--...  n$$%7$II	''W'== "z$))++"4"4"6"677&t,,/1%(UU! ( (D>tDD ! "488D>>#7R88>>@@H# !x8';'; LL***MM$'''' "!" " " " " " " " " """ " " " " " " " " " " " " " "  	 	 	H	4s=   <!FCF4FFF	FF	F
F+*F+zdict[str, int]_copilot_context_cacheg        _copilot_context_cache_timei  Optional[int]c                J   t           r<t          j                    t          z
  t          k     r| t           v rt           |          S dS t	          |          }|sdS i }|D ]}t          |                    d          pd                                          }|s;|                    d          pi }|                    d          pi }|                    d          }t          |t                    r|dk    r|||<   |a t          j                    a|                    |           S )	zLook up max_prompt_tokens for a Copilot model from the live /models API.

    Results are cached in-process for 1 hour to avoid repeated API calls.
    Returns the token limit or None if not found.
    Nr  r_  r   r  limitsmax_prompt_tokensr   )
r  r   r  _COPILOT_CONTEXT_CACHE_TTLr  rQ   rW   r   rP   r   )	r   r  catalogr  rT  rS   capsr  
max_prompts	            rE   get_copilot_model_contextr    s+     49;;1L#LOi#i#i---)(33t )999G tE $ $$((4..&B''--// 	xx''-2(##)rZZ 344
j#&& 	$:>>#E#J""&)++99XrG   c                    | pd                                                     d                                          }|                    t                    p|                    d          S )Nr   r   z"https://models.github.ai/inference)r   r   r  r|  COPILOT_BASE_URL)r  r  s     rE   _is_github_models_base_urlr    s`    .b''))0055;;==J.// 	G  !EFFrG   c                    | pd                                                     d          }|                    d          r|dd                             d          }|pdS )zStrip ``/v1`` suffix from an LM Studio base URL to get the native API root.

    Returns ``None`` when the base URL is empty/invalid.
    r   r   r  Nr  )r   r   r  )r  roots     rE   _lmstudio_server_rootr    s`    
 N!!##**3//D}}U %CRCy$$<4rG   rV   c                r    dt           i}t          | pd                                          }|rd| |d<   |S )z5Build HTTP headers for LM Studio native API requests.r  r   r   r   )r  rQ   r   )r  r   r  s      rE   _lmstudio_request_headersr    sI    /0G2$$&&E 5#4U#4#4 NrG   Optional[list[dict]]c                   t          |          }|sdS t          |           }t          j                            |dz   |          }	 t          j                            ||          5 }t          j        |                                	                                          }ddd           n# 1 swxY w Y   n# t          j
        j        $ rj}|j        dv rddlm}	  |	d|j         d	d
d          |ddl}
|
                    t"                                        d||j                   Y d}~dS d}~wt&          $ r>}ddl}
|
                    t"                                        d||           Y d}~dS d}~ww xY wt)          |t*                    r|                    d          nd}t)          |t.                    s4ddl}
|
                    t"                                        d|           dS |S )zFetch the raw model list from LM Studio's ``/api/v1/models``.

    Returns the ``models`` list of dicts on success, ``None`` on network
    errors or malformed responses.  Raises ``AuthError`` on HTTP 401/403.
    Nz/api/v1/modelsr   r   )i  i  r   	AuthErrorz)LM Studio rejected the request with HTTP .r  auth_rejected)rK  r  z)LM Studio probe at %s failed with HTTP %sz LM Studio probe at %s failed: %srM   zCLM Studio probe at %s returned malformed payload (no `models` list))r  r  r   r   r   r   r   r   r   r   r  r  r  r   r  r  r  r  r  rZ   rP   rV   rW   rD   )r  r  r   server_rootr   r   r   r   excr  r  
raw_modelss               rE   _lmstudio_fetch_raw_modelsr    sw    (11K t'00Gn$$[3C%CW$UUG^##GW#== 	7j!3!3!5!566G	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7<!   8z!!111111)GCHGGG#$   	
 	(##))7ch	
 	
 	
 ttttt   (##)).S	
 	
 	
 ttttt +5Wd*C*CMX&&&Jj$'' (##))Q	
 	
 	
 tsI   !B: )9B."B: .B22B: 5B26B: :E>AD33E> 3E99E>c                   t          | ||          }|dS g }|D ]}t          |t                    st          |                    d          pd                                                                          dk    ret          |                    d          p|                    d          pd                                          }|r||vr|                    |           |S )a  Probe LM Studio's model listing.

    Returns chat-capable model keys on success, including the valid empty-list
    case when the server is reachable but has no non-embedding models.
    Returns ``None`` on network errors, malformed responses, or empty/invalid
    base URLs.

    Raises ``AuthError`` on HTTP 401/403 so callers can surface token issues
    separately from reachability problems.
    r  r  r   Nr  r   	embeddingr  r_  )r  rP   rV   rQ   rW   r   r  r   )r  r  r   r  rX   r  r  s          rE   probe_lmstudio_modelsr  	  s     ,GhX_```JtD  #t$$ 	swwv$"%%++--3355DD#''%..7CGGDMM7R88>>@@ 	3d??KKKrG   c                .    t          | ||          }|pg S )u  Fetch LM Studio chat-capable model keys from native ``/api/v1/models``.

    Returns a list of model keys (e.g. ``publisher/model-name``) with embedding
    models filtered out. Returns an empty list on network errors, malformed
    responses, or empty/invalid base URLs.

    Raises ``AuthError`` on HTTP 401/403 so callers can distinguish a missing
    or wrong ``LM_API_KEY`` from an unreachable server — the most common
    LM Studio support case once auth-enabled mode is turned on.
    r  )r  )r  r  r   rM   s       rE   fetch_lmstudio_modelsr  $	  s"     #7XwWWWF<RrG         ^@r  target_context_lengthc                p   t          |          }|sdS t          |          }	 t          ||d          }n# t          $ r d}Y nw xY w|dS d}|D ]N}	t	          |	t
                    s|	                    d          | k    s|	                    d          | k    r|	} nO|dS |                    d          }
t	          |
t                    r|
dk    rt          ||
          }|                    d          pg D ]y}t	          |t
                    r|                    d	          nd}t	          |t
                    r|                    d
          nd}t	          |t                    r
||k    r|c S zt          j
        | |d                                          }t          |          }d|d<   	 t          j                            t          j                            |dz   ||d          |          5 }|                                 ddd           n# 1 swxY w Y   n# t          $ r Y dS w xY w|S )aw  Ensure LM Studio has ``model`` loaded with at least ``target_context_length``.

    No-op when an instance is already loaded with sufficient context. Otherwise
    POSTs ``/api/v1/models/load`` to (re)load with the target context, capped
    at the model's ``max_context_length``. Returns the resolved loaded context
    length, or ``None`` when the probe / load failed.
    N
   r  r  r_  max_context_lengthr   loaded_instancesr  context_length)r  r  r   zContent-Typez/api/v1/models/loadPOST)r[   r   methodr   )r  r  r  rZ   rP   rV   rW   r   minr   dumpsencoder   r   r   r   r   )r  r  r  r  r   r  r   r  target_entryr  max_ctxinstcfg
loaded_ctxbodyload_headersr   s                    rE   ensure_lmstudio_model_loadedr  7	  s    (11K t'00G/(\^___

   


tL  #t$$ 	775>>U""cggdmmu&<&<LE '= t344G'3 DGaKK #$97 C C  !344:  $.tT$:$:Ddhhx   2<S$2G2GQSWW-...T
j#&& 	:9N+N+N:/    vxx 	 ==L#5L ^##N""33$	 #    $ 
 
 		 IIKKK		 		 		 		 		 		 		 		 		 		 		 		 		 		 		    tt  sF   7 AA3AH% 8HH% HH%  H!H% %
H32H3c                   	 t          |||          }n# t          $ r d}Y nw xY w|sg S |D ]}t          |t                    s|                    d          | k    r|                    d          | k    rK|                    d          }t          |t                    r|                    d          nd}t          |t                    r|                    d          nd}t          |t
                    rd |D             c S g c S g S )	a$  Return the reasoning ``allowed_options`` LM Studio publishes for ``model``.

    Pulls ``capabilities.reasoning.allowed_options`` from ``/api/v1/models``.
    Returns ``[]`` when the model is unknown, the endpoint is unreachable,
    or the model does not declare a reasoning capability.
    r  Nr  r_  r  	reasoningallowed_optionsc                    g | ]J}t          |t                    t          |                                                                          KS rO   )rP   rQ   r   r  )rR   os     rE   rT   z4lmstudio_model_reasoning_options.<locals>.<listcomp>	  sA    OOOqJq#<N<NOCFFLLNN((**OOOrG   )r  rZ   rP   rV   rW   rD   )	r  r  r  r   r  r  r  r
  optss	            rE    lmstudio_model_reasoning_optionsr  |	  s7   /(\cddd

   


 	 
 
#t$$ 	775>>U""swwt}}'='=ww~&&-7d-C-CMDHH[)))	3=i3N3NXy}}.///TXdD!! 	POODOOOOOO			Is    $$c                D    t          | |          }|sd S d |D             S )Nr  r   c                d    g | ]-}|                     d           |                     d d          .S r_  r   r  r  s     rE   rT   z(_fetch_github_models.<locals>.<listcomp>	  s5    EEE4dhhtnnEDHHT2EEErG   )r  )r  r   r  s      rE   r{  r{  	  s5    ('JJJG tEE7EEEErG   zopenai/gpt-5rc   zopenai/gpt-5-chatzopenai/gpt-5-minizopenai/gpt-5-nanozopenai/gpt-4.1rf   zopenai/gpt-4.1-minizopenai/gpt-4.1-nanozopenai/gpt-4org   zopenai/gpt-4o-minirh   	openai/o1r   zopenai/o1-minizopenai/o1-preview	openai/o3rd   zopenai/o3-minizopenai/o4-minir   zclaude-opus-4.6r   rl   rm   rn   ro   )zanthropic/claude-sonnet-4r   r   r   r   zclaude-sonnet-4-0r   r   zanthropic/claude-opus-4-6zanthropic/claude-sonnet-4-6zanthropic/claude-sonnet-4-0zanthropic/claude-sonnet-4-5zanthropic/claude-haiku-4-5r  c                b    | |rt          |          } | st                      S d | D             S )Nr  c                    h | ]n}t          |                    d           pd                                          8t          |                    d           pd                                          oS r  )rQ   rW   r   r  s     rE   r  z'_copilot_catalog_ids.<locals>.<setcomp>	  st       txx~~#$$**,,DHHTNN b!!''))  rG   )r  rk  r  r  s     rE   _copilot_catalog_idsr  	  sO     7,W=== uu    rG   r  c               p   t          | pd                                          }|sdS t          ||          }t                              |          }|r|S |g}d|v rA|                    |                    dd          d                                                    |                    d          r|                    |d d                    |                    d          r|                    |d d                    |                    d          r|                    |d d                    t                      }|D ]>}|r||v r	|	                    |           |t          v rt          |         c S ||v r|c S ?d|v r.|                    dd          d                                         S |S )	Nr   r  r   r  z-miniz-nanoz-chat)
rQ   r   r  _COPILOT_MODEL_ALIASESrW   r   r6  r  rk  rl  )	r   r  r  r  catalog_idsr  r  seen	candidates	            rE   normalize_copilot_model_idr   	  s    hn"


#
#
%
%C r&wHHHK"&&s++E J
czz#))C++A.4466777
||G $#crc(###
||G $#crc(###
||G $#crc(###UUD  	 	I--...))4444## $ czzyya  #))+++JrG   c                <   | pd                                                                 }|                    d          rt          t                    S t          |                                           }|                    d          rt          t                    S g S )Nr   )r  r  z	openai/o4r>  r?  r@  r   )r   r  r|  rD   "COPILOT_REASONING_EFFORTS_O_SERIESr   COPILOT_REASONING_EFFORTS_GPT5)r   r  r  s      rE   &_github_reasoning_efforts_for_model_idr$  
  s    >r
 
 
"
"
(
(
*
*C
~~OPP 86777+H55;;==JW%% 42333IrG   c                    ddl }|                    d|           }|sdS t          |                    d                    }|dk    o|                     d           S )a%  Decide whether a Copilot model should use the Responses API.

    Replicates opencode's ``shouldUseCopilotResponsesApi`` logic:
    GPT-5+ models use Responses API, except ``gpt-5-mini`` which uses
    Chat Completions.  All non-GPT models (Claude, Gemini, etc.) use
    Chat Completions.
    r   Nz
^gpt-(\d+)Fr  r  rc   )rematchr   groupr|  )r   r&  r'  majors       rE   !_should_use_copilot_responses_apir*  
  sd     IIIHH]H--E uAEA:?h11,????rG   c               :   ||rt          |          }t          | ||          sdS t                    rdS |r\t          fd|D             d          }t	          |t
                    r+d |                    d          pg D             }d	|v rd
|vrdS dS )zDetermine the API mode for a Copilot model.

    Uses the model ID pattern (matching opencode's approach) as the
    primary signal.  Falls back to the catalog's ``supported_endpoints``
    only for models not covered by the pattern check.
    Nr  r  chat_completionscodex_responsesc              3  N   K   | ]}|                     d           k    |V   dS r_  Nr  rR   rT  r  s     rE   r}  z)copilot_model_api_mode.<locals>.<genexpr>9
  7      WWt$((4..J:V:Vd:V:V:V:VWWrG   c                    h | ]D}t          |                                          #t          |                                          ES rO   r  r  s     rE   r  z)copilot_model_api_mode.<locals>.<setcomp>;
  sR     # # #x==&&((#H##%%# # #rG   r  r  r  anthropic_messages)r  r   r*  r  rP   rV   rW   )r   r  r  catalog_entryr  r  s        @rE   copilot_model_api_moder5  
  s     7,W===+HgwWWWJ "!! )44 !    
,WWWWwWWWY]^^mT** 	,# #!.!2!23H!I!I!OR# # # !4449LTg9g9g++rG   )rC  r   r>  r?  r@  c                    t          | pd                                                                          }|sdS d|v r|                    dd          d         }t          D ]}|                    |          r dS dS )u  Infer Azure Foundry api_mode from a deployment/model name.

    Returns ``"codex_responses"`` when the model name matches a family that
    only accepts the Responses API on Azure Foundry (GPT-5.x, codex, o1/o3/o4
    reasoning models).  Returns ``None`` otherwise — the caller should fall
    back to the configured/default api_mode (typically ``chat_completions``)
    so GPT-4o, GPT-4 Turbo, Llama, Mistral, etc. keep working.

    Intentionally does NOT return ``anthropic_messages``; Anthropic-style
    Azure endpoints are disambiguated by URL (``/anthropic`` suffix) in
    ``runtime_provider._detect_api_mode_for_url`` and by the user setting
    ``model.api_mode: anthropic_messages`` explicitly.
    r   Nr   r  r-  )rQ   r   r  rsplit!_AZURE_FOUNDRY_RESPONSES_PREFIXESr|  )r  r  r!  s      rE   azure_foundry_model_api_moder:  X
  s     jB


%
%
'
'
-
-
/
/C t
czzjja  $ 4 % %>>&!! 	%$$$	%4rG   provider_idc                    t          |           }t          |pd                                          }|r|dvr|S | d}|                                                    |          r|t          |          d         S |S )zJNormalize OpenCode config IDs to the bare model slug used in API requests.r   >   r   r   r   N)r  rQ   r   r  r|  r  )r;  r   rK  currentr!  s        rE   normalize_opencode_model_idr>  u
  s    !+..H(.b!!''))G h&EEE^^^F}}!!&)) %s6{{||$$NrG   c                   t          |           }t          | |                                          }|sdS |dk    r|                    d          rdS dS |dk    r0|                    d          rdS |                    d          rdS dS dS )	a  Determine the API mode for an OpenCode Zen / Go model.

    OpenCode routes different models behind different API surfaces:

    - GPT-5 / Codex models on Zen use ``/v1/responses``
    - Claude models on Zen use ``/v1/messages``
    - MiniMax models on Go use ``/v1/messages``
    - GLM / Kimi on Go use ``/v1/chat/completions``
    - Other Zen models (Gemini, GLM, Kimi, MiniMax, Qwen, etc.) use
      ``/v1/chat/completions``

    This follows the published OpenCode docs for Zen and Go endpoints.
    r,  r   zminimax-r3  r   rN  r=  r-  )r  r>  r  r|  )r;  r   rK  r  s       rE   opencode_model_api_moder@  
  s     "+..H,[(CCIIKKJ "!!=    ,, 	(''!!>!!  ++ 	(''  (( 	%$$!!rG   c                 
 t          | ||          

sg S d}|t          
fd|D             d          }n0|r.t          |          }|rt          
fd|D             d          }||                    d          }t	          |t
                    r|                    d          }t	          |t
                    r]|                    d          }t	          |t                    r3d	 |D             }t          t
                              |                    S g S d
 |                    dg           D             }	d|	vrg S t          t          | p
                    S )zEReturn supported reasoning-effort levels for a Copilot-visible model.r  Nc              3  N   K   | ]}|                     d           k    |V   dS r/  r  r0  s     rE   r}  z1github_model_reasoning_efforts.<locals>.<genexpr>
  r1  rG   r  c              3  N   K   | ]}|                     d           k    |V   dS r/  r  r0  s     rE   r}  z1github_model_reasoning_efforts.<locals>.<genexpr>
  s8      !c!c4dhhtnnXbFbFb$FbFbFbFb!c!crG   r  supportsreasoning_effortc                    g | ]V}t          |                                          #t          |                                                                          WS rO   rQ   r   r  )rR   efforts     rE   rT   z2github_model_reasoning_efforts.<locals>.<listcomp>
  s^     * * *"v;;,,..*F))++1133* * *rG   c                    h | ]V}t          |                                          #t          |                                                                          WS rO   rG  )rR   
capabilitys     rE   r  z1github_model_reasoning_efforts.<locals>.<setcomp>
  s^     
 
 
:$$&&

OO!!##))++
 
 
rG   r
  )
r   r  r  rW   rP   rV   rD   fromkeysr$  rQ   )r   r  r  r4  fetched_catalogr  rD  effortsnormalized_effortslegacy_capabilitiesr  s             @rE   github_model_reasoning_effortsrP  
  s    ,HgwWWWJ 	MWWWWwWWWY]^^	 k4WEEE 	k !c!c!c!c?!c!c!ceijjM $((88lD)) 	#''
33H(D)) C",,'9::gt,, C* *&-* * *&
  .@ A ABBBI
 
+//CC
 
 

 111I1#h6L*2M2MNNNrG   api_modec                   |pd                                                     d          }|sddddddS t          |          r#t          | |          }|t          t
          dddS |                    d          r|dd                             d          }n|dz   }|dfg}|r||k    r|                    |d	f           g }d
t          i}	| r|dk    r| |	d<   d|	d<   n
| rd|  |	d<   |	                    t
                    r!|	
                    t                                 |D ]\  }
}|
                    d          dz   }|                    |           t          j                            ||	          }	 t          j                            ||          5 }t!          j        |                                                                          }d |                    dg           D             ||
                    d          ||
k    r|n||dcddd           c S # 1 swxY w Y   # t*          $ r Y w xY wd|r|d         n|                    d          dz   |||k    r|ndddS )a8  Probe a ``/models`` endpoint with light URL heuristics.

    For ``anthropic_messages`` mode, uses ``x-api-key`` and
    ``anthropic-version`` headers (Anthropic's native auth) instead of
    ``Authorization: Bearer``.  The response shape (``data[].id``) is
    identical, so the same parser works for both.
    r   r   NF)rM   
probed_urlresolved_base_urlsuggested_base_urlused_fallbackr  r  r  Tr  r3  r  r  r  r   r   r
   r   r   c                :    g | ]}|                     d d          S r  r  r	  s     rE   rT   z$probe_api_models.<locals>.<listcomp>  s$    MMM1quuT2MMMrG   r[   r   )r   r   r  r{  r  r  r  r   r  r|  updater  r   r   r   r   r   r   r   r   rW   rZ   )r  r  r   rQ  r  rM   alternate_baser  triedr   candidate_baseis_fallbackr   r   r   r[   s                   rE   probe_api_modelsr]  
  sO    .b''))0055J 
!#"&"
 
 	
 "*-- 
%gwGGG,!1"&"
 
 	
 5!! ,#CRC//44#e++5u*=)>J 2.J66>40111E+-?@G 78333&'3#$$	 7#6W#6#6 -.. 2.00111'1  ###C((94Sn$$S'$::	''W'== z$))++"4"4"6"677MM8L8LMMM"%)7)>)>s)C)C<Jn<\<\..bl%0                     	 	 	H	 "'OeAhhZ->->s-C-Ci-O'0>*0L0LnnRV  s7   <!H2A9H%H2%H)	)H2,H)	-H22
I ?I c                   t          j        dd                                          }|sdS t          j        dd                                          }|sddlm} |}|                    d          dz   }d	| t          d
}t          j        	                    ||          }	 t          j        
                    ||           5 }t          j        |                                                                          }d |                    dg           D             cddd           S # 1 swxY w Y   dS # t           $ r Y dS w xY w)z>Fetch available language models with tool-use from AI Gateway.AI_GATEWAY_API_KEYr   Nry  r   rx  r   r
   r   )r   r  r   r   c                    g | ]Q}|                     d           r:|                     d          dk    r!d|                     d          pg v I|d          RS )r_  r  languageztool-usetagsr  r	  s     rE   rT   z,_fetch_ai_gateway_models.<locals>.<listcomp>1  sk       55;; EE&MMZ//155==#6B77	 $ 877rG   r[   )r  r  r   r  ry  r   r  r   r   r   r   r   r   r   r   rW   rZ   )	r   r  r  ry  r   r   r   r   r[   s	            rE   r~  r~    s   i,b117799G ty.3399;;H '888888&
//#


*C,7,,( G .
 
 g
 
6
6C^##C#99 	T:diikk002233D &"--  	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	    tts7   $!D7 AD*D7 *D..D7 1D.2D7 7
EEc                N    t          | |||                              d          S )zFetch the list of available model IDs from the provider's ``/models`` endpoint.

    Returns a list of model ID strings, or ``None`` if the endpoint could not
    be reached (network error, timeout, auth failure, etc.).
    )r   rQ  rM   )r]  rW   )r  r  r   rQ  s       rE   r|  r|  <  s*     GXwRRRVVW_```rG   r   c                 (    ddl m}   |             dz  S )z1Return the path for the Ollama Cloud model cache.r   get_hermes_homezollama_cloud_models_cache.json)r  rf  re  s    rE   _ollama_cloud_cache_pathrg  S  s(    000000????rG   
ignore_ttlri  Optional[dict]c                   	 t                      }|                                sdS t          |d          5 }t          j        |          }ddd           n# 1 swxY w Y   t          |t                    sdS |                    d          }t          |t                    r|sdS | s7|                    dd          }t          j	                    |z
  t          k    rdS |S # t          $ r Y nw xY wdS )zLoad cached Ollama Cloud models from disk.

    Args:
        ignore_ttl: If True, return data even if the TTL has expired (stale fallback).
    Nzutf-8)encodingrM   r   r   )rg  existsopenr   loadrP   rV   rW   rD   r   _OLLAMA_CLOUD_CACHE_TTLrZ   )ri  
cache_pathfr[   rM   r   s         rE   _load_ollama_cloud_cachers  Y  sD   -//
  "" 	4*w/// 	 19Q<<D	  	  	  	  	  	  	  	  	  	  	  	  	  	  	 $%% 	4(##64(( 	V 	4 	a00I	i'+BBBt   4sK   "C# C# AC# AC# A C# :,C# (7C# !C# #
C0/C0Nonec                    	 ddl m} t                      }|j                            dd            ||| t          j                    dd           dS # t          $ r Y dS w xY w)z3Persist the merged Ollama Cloud model list to disk.r   )atomic_json_writeT)parentsexist_ok)rM   r   N)r  )utilsrv  rg  parentmkdirr   rZ   )rM   rv  rq  s      rE   _save_ollama_cloud_cacher|  t  s    ++++++-//
t<<<*dikk&R&R[_``````   s   AA 
A$#A$c               n   |st                      }||d         S | st          j        dd          } |st          j        dd          pd}g }| rt          | |d          }|r|}g }	 d	d
lm}  |d          }n# t          $ r Y nw xY w|s|rt                      }g }	|D ]2}
|
r.|
|vr*|                    |
           |		                    |
           3|D ]2}
|
r.|
|vr*|                    |
           |		                    |
           3|	rt          |	           |	S t          d          }||d         S g S )u  Fetch Ollama Cloud models by merging live API + models.dev, with disk cache.

    Resolution order:
      1. Disk cache (if fresh, < 1 hour, and not force_refresh)
      2. Live ``/v1/models`` endpoint (primary — freshest source)
      3. models.dev registry (secondary — fills gaps for unlisted models)
      4. Merge: live models first, then models.dev additions (deduped)

    Returns a list of model IDs (never None — empty list on total failure).
    NrM   OLLAMA_API_KEYr   OLLAMA_BASE_URLzhttps://ollama.com/v1rZ  r   r   ri  r$  Trh  )rs  r  r  r|  rU   rj  rZ   rk  rl  r   r|  )r  r  r   r   live_modelsr   mdev_modelsrj  r  ro  r
  stales               rE   r  r    s   "  $)++(##  2),b11 O9.33N7NK !!'8SAAA 	! K  K888888)).99     k  	! 	!A !Qd]]a    	! 	!A !Qd]]a    	$V,,,M %555EXIs   (A: :
BB)r  r  rQ  c          
        | pd                                 }t          |          }|dk    r|rd|vrd}|}|dk    rt          ||          p|}|sddddd	S t          d
 |D                       rddddd	S |dk    rrddlm} 	 t          ||          }	n# |$ r}
ddd|
 dd	cY d}
~
S d}
~
ww xY w|	dddd| dd	S |	sdddd| dd	S |t          |	          v rddddd	S dddd| dd	S |dk    rz|dk    rt          |||          }nt          ||          }|	                    d          }||t          |          v rddddd	S t          ||dd          }|rddd|d         d| d |d          d!d"S t          ||d#d$          }d}|r"d%d&                    d' |D                       z   }d(| d)|	                    d*           d+| }|	                    d,          r|d-|	                    d.           d/z  }ddd|d	S d0|	                    d*           d1| d2}|dk    r|d3z  }|	                    d4          r|d5|	                    d4           d!z  }|dk    dd|d	S |d6k    r	 t          d6          }n# t          $ r g }Y nw xY w|r|t          |          v rddddd	S t          ||dd          }|rddd|d         d| d |d          d!d"S t          ||d#d$          }d}|r"d%d&                    d7 |D                       z   }dddd| d8| d	S |d9v r	 t          |          }n# t          $ r g }Y nw xY w|rd: |D             |                                v rddddd	S t                                                    }t          |                                |dd          }|r|d                  }ddd|d| d | d!d"S t          |                                |d#d$          }d}|r$d%d&                    fd;|D                       z   }dddd(| d<| d=d	S |d>k    rt#                      }||t          |          v rddddd	S t          ||dd          }|rddd|d         d| d |d          d!d"S t          ||d#d$          }d}|r"d%d&                    d? |D                       z   }dddd(| d@| d	S |dk    rgt%          |||          }|H|t          |          v rddddd	S t          ||dd          }|rddd|d         d| d |d          d!d"S ddddA| dBd	S t%          ||          }||dCk    rdD |D             }|t          |          v rddddd	S t          ||dd          }|rddd|d         d| d |d          d!d"S t          ||d#d$          }d}|r"d%d&                    dE |D                       z   }dddd| dF| d	S |dGk    r	 ddHlm}m}  |            } ||          }dI |D             }||v rddddd	S t          |t          |          d#dJ          }d}|r"d%d&                    dK |D                       z   }dddd(| dL| dM| d	S # t          $ r Y nw xY wt,          	                    ||          }	 t          |          }n# t          $ r g }Y nw xY w|rdN |D             |                                v rddddd	S t                                                    }t          |                                |dd          }|r|d                  }ddd|d| d | d!d"S t          |                                |d#d$          }d}|r$d%d&                    fdO|D                       z   }dddd(| dP| dQ| dRd	S ddddS| dT| dUd	S )Va  
    Validate a ``/model`` value for the active provider.

    Performs format checks first, then probes the live API to confirm
    the model actually exists.

    Returns a dict with:
      - accepted: whether the CLI should switch to the requested model now
      - persist: whether it is safe to save to config
      - recognized: whether it matched a known provider catalog
      - message: optional warning / guidance for the user
    r   r  zopenrouter.air)  rk   r  FzModel name cannot be empty.)acceptedpersist
recognizedmessagec              3  >   K   | ]}|                                 V  d S r  )isspace)rR   chs     rE   r}  z+validate_requested_model.<locals>.<genexpr>  s*      
,
,B2::<<
,
,
,
,
,
,rG   z"Model names cannot contain spaces.r  r   r  )r  r  zD Set `LM_API_KEY` (or update it) to match the server's bearer token.Nz:Could not reach LM Studio's `/api/v1/models` to validate `z`.zDLM Studio is reachable but no chat-capable models are loaded. Load `u<   ` in LM Studio (Developer tab → Load Model) and try again.TzModel `z-` was not found in LM Studio's model listing.r3  )rQ  rM   r  g?)ncutoffzAuto-corrected `u   ` → ``)r  r  r  corrected_modelr  r  g      ?z
  Similar models: z, c              3  "   K   | ]
}d | d V  dS r  NrO   rR   ss     rE   r}  z+validate_requested_model.<locals>.<genexpr>0  +      DcDcRSXXXXDcDcDcDcDcDcrG   zNote: `z9` was not found in this custom endpoint's model listing (rS  zE). It may still work if the server supports hidden or aliased models.rV  z1
  Endpoint verification succeeded after trying `rT  z)`. Consider saving that as your base URL.z?Note: could not reach this custom endpoint's model listing at `z`. Hermes will still save `z=`, but the endpoint should expose `/models` for verification.z
  Many Anthropic-compatible proxies do not implement the Models API (GET /v1/models).  The model name has been accepted without verification.rU  z0
  If this server expects `/v1`, try base URL: `ri   c              3  "   K   | ]
}d | d V  dS r  rO   r  s     rE   r}  z+validate_requested_model.<locals>.<genexpr>r  r  rG   z2` was not found in the OpenAI Codex model listing.)r   r   c                8    i | ]}|                                 |S rO   r+  r	  s     rE   r(  z,validate_requested_model.<locals>.<dictcomp>  s"    BBBaQWWYYBBBrG   c              3  0   K   | ]}d |          d V  dS r  rO   rR   r  catalog_lowers     rE   r}  z+validate_requested_model.<locals>.<genexpr>  s6      DrDrabE\WXIYE\E\E\DrDrDrDrDrDrrG   z'` was not found in the MiniMax catalog.z
  MiniMax does not expose a /models endpoint, so Hermes cannot verify the model name.
  The model may still work if it exists on the server.r   c              3  "   K   | ]
}d | d V  dS r  rO   r  s     rE   r}  z+validate_requested_model.<locals>.<genexpr>  r  rG   zn` was not found in Anthropic's /v1/models listing. It may still work if you have early-access or snapshot IDs.zNote: could not verify `z` against this endpoint's model listing.  Many Anthropic-compatible proxies do not implement GET /v1/models.  The model name has been accepted without verification.rs   c                    g | ]E}t          |t                    r,|                    d           r|t          d           d         n|FS )zmodels/N)rP   rQ   r|  r  r	  s     rE   rT   z,validate_requested_model.<locals>.<listcomp>  s]        '1C&8&8[Q\\)=T=T[#i..//""Z[  rG   c              3  "   K   | ]
}d | d V  dS r  rO   r  s     rE   r}  z+validate_requested_model.<locals>.<genexpr>$  r  rG   z1` was not found in this provider's model listing.r   )discover_bedrock_modelsresolve_bedrock_regionc                    h | ]
}|d          S r  rO   r	  s     rE   r  z+validate_requested_model.<locals>.<setcomp>;  s    :::!ag:::rG   g?c              3  "   K   | ]
}d | d V  dS r  rO   r  s     rE   r}  z+validate_requested_model.<locals>.<genexpr>H  r  rG   z/` was not found in Bedrock model discovery for zK. It may still work with custom inference profiles or cross-account access.c                8    i | ]}|                                 |S rO   r+  r	  s     rE   r(  z,validate_requested_model.<locals>.<dictcomp>f  s"    >>>!A>>>rG   c              3  0   K   | ]}d |          d V  dS r  rO   r  s     rE   r}  z+validate_requested_model.<locals>.<genexpr>  sM       A A,-'M!$'''A A A A A ArG   z` was not found in the z: curated catalog and the /models endpoint was unreachable.z9
  The model may still work if it exists on the provider.zNote: could not reach the z API to validate `z:`. If the service isn't down, this model may not be valid.)r   r  r   r  r   r  r  rk  r]  rW   r   r  r  rZ   r  rD   rX   r}  r|  r  r  r  r  )r  rK  r  r  rQ  	requestedr  requested_for_lookupr  rM   r  probe
api_modelsr9  suggestionssuggestion_textr  codex_modelscatalog_modelscatalog_lower_list	correctedanthropic_modelsr  r  region
discovereddiscovered_idsr<  r  s                               @rE   validate_requested_modelr    s   ( !r((**I#H--J\!!h!?(3R3R
$Y9 
  
  
    	
  
4	
 
 	
 
,
,)
,
,
,,, 
;	
 
 	
 Z------	*7XNNNFF 	 	 	!e5```       	 >!e5eXaeee    	!e5e&e e e    3v;;.. $TVZ[[[%uYYYY
 
 	

 X+++$WhJJJEE$Wh77EYYx((
!#s:66 $#"&#	   %%9:SVWWWD  $#"&'+AwN)NNDGNNN   ,IzQsSSSK O d"8499DcDcWbDcDcDc;c;c"c%) % %IIl++% %"% % 
 yy)) >SfIgIg > > > !#"	  peiiXdNeNe p p'0p p p 	 +++\G 99)** 	nm599UiKjKjmmmmG !$88	
 
 	
 ^##	-n==LL 	 	 	LLL	 	#s<'8'888 $#"&#	   %%9<1UXYYYD  $#"&'+AwN)NNDGNNN   ,,@,RS\_```K O d"8499DcDcWbDcDcDc;c;c"c! #)i ) )&) )   ...	 /
;;NN 	  	  	 NNN	  $	BB>BBBM#))++}<< $#"&#	   "&m&8&8&:&:!;!;$%9%?%?%A%ACUYZcfgggD )$q'2	 $#"&'0P)PPIPPP   ,,@,F,F,H,HJ\`ajmnnnK O s"8499DrDrDrDrfqDrDrDr;r;r"r #Oi O O&O O O
 
 
$ [  244'#s+;'<'<<< $#"&#	   %%9;KqY\]]]D  $#"&'+AwN)NNDGNNN   ,I7G1UXYYYK O d"8499DcDcWbDcDcDc;c;c"c
 !#)i ) )&) )	 	 	 '''%gx(KKK
!#s:66 $#"&#	   %%9:SVWWWD  $#"&'+AwN)NNDGNNN   )9 ) ) )

 

 
	
 "'844J !! #  J  3z??22 !"	   %%9:SVWWWD  $#"&'+AwN)NNDGNNN   ,IzQsSSSK O d"8499DcDcWbDcDcDc;c;c"c %) % %"% %
 
 	
  Y	]]]]]]]]++--F0088J::z:::NN** $#"&#	   ,ItN7K7KqY\]]]K O d"8499DcDcWbDcDcDc;c;c"c #)i ) )X^ ) )&) )	 	 	  	 	 	D	 &))*jAAN+J77     '
>>~>>>%%''=88 "	   "-"4"4"6"677  &&((*<#
 
 
  	%d1g.I "#,LiLL	LLL   ( &&((*<#
 
 
  	4tyy A A A A1<A A A 8 8 O N) N NN N N<KN N N	
 	
 		
 G G G9 G G G  sm   B B1	B,&B1,B19J	 	JJ1M MM3Z <AZ 
ZZ>[ [[)r=   r>   )r   rQ   r   r   r=   r   r  )r   rQ   r   rQ   r=   r   )r   r   r=   r   )r   r>   r   r   r   r   r=   r   )r=   r   )r   r   )r   rQ   r   r   r   r   r=   r   )r=   rQ   )r  r   r=   r  )
r  r   r   r  r   rQ   r   r   r=   r  )rK  rQ   r=   rQ   )r   r   r=   r   )rT  r   r=   r   )rZ  )r   r   r   r   r=   r7   )r   r   r=   r>   )r  rQ   r=   rQ   )r   r  )
rM   r7   r  r   r  rQ   r  rQ   r=   r>   )Nr  rZ  )
r  r  r  rQ   r   r   r   r   r=   r   )r   r   r   r   r=   r   )r=   r  )rK  rQ   r   r   r=   r   )r=   r  )r  rQ   r  rQ   r=   r  )rK  r  r   r   r=   r7   )rK  rQ   r=   r  )r  rQ   r  r  r=   r   )r  rQ   r  r  r=   r  )r  rQ   r  rQ   r=   r  )r  rQ   r=   r  )rK  r  r=   rQ   )r   r  r=   r   )r   rQ   r=   rQ   )r   r  r=   rO  )rK  rQ   rf  r>   r=   r>   )rK  r  r   r   r=   r>   )r   )r   r   r=   r  )r   r   r=   r  )r=   r  )rT  r   r=   r   )Nr   )r  r  r   r   r=   r  r  )r   rQ   r  r  r=   r  )r  r  r=   r   )r  r  r=   r  )r  r  r=   rV   )NNr   )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  rQ   r  r  r  r  r  r   r   r   r=   r  )
r  rQ   r  r  r  r  r   r   r=   r>   )r  r  r   r   r=   r  )NN)r  r  r  r  r=   r  )r   r  r  r  r  r  r=   rQ   )r   rQ   r=   r>   )r   rQ   r=   r   )r  r  r=   r  )r;  r  r   r  r=   rQ   )r   r  r  r  r  r  r=   r>   )r   N)
r  r  r  r  r   r   rQ  r  r=   r   )
r  r  r  r  r   r   rQ  r  r=   r  )r=   r   )ri  r   r=   rj  )rM   r>   r=   rt  )r  r  r  r  r   r   r=   r>   )r  rQ   rK  r  r  r  r  r  rQ  r  r=   r   )__doc__
__future__r   r   r  urllib.requestr   urllib.errorr   difflibr   pathlibr   typingr   r   r   
hermes_clir	   _HERMES_VERSIONr  r  r  r  r#  r"  r8   r  r9   r;   r<   rF   rI   r]   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r%  r  r  rM  rR  rY  rk  r   rr  rv  r  r  r  r  r  r  r  r  r  r  rk  rX   r  r  r  r  r  r  r  	frozensetr   r(  r/  r4  r1  r  r<  rA  rG  rE  rL  rJ  rU  r`  rg  rp  r  r}  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r{  r  r  r   r$  r*  r5  r9  r:  r>  r@  rP  r]  r~  r|  rp  rg  rs  r|  r  r  rO   rG   rE   <module>r     s     # " " " " "  				          % % % % % %       , , , , , , , , , , 5 5 5 5 5 5 5?44 2 (111 ) !E!E!E %>%>%> "
$, $, $,  $ $ $ $L ;?  > > > >3 3 3     $ ;?  > > > >B B B B 
# 
# 
#  
 
 
 
& & & &6b*
   b*F  	 	 	Gb*Z ))++[b*\ ]b*b    cb*H    Ib*T    Ub*^ 
   _b*p 
  qb*r    sb*N    Ob*`    ab*n ob*v    wb*D    Eb*P  Qb*X    Yb*d	 	 	     	  
  $ $ $J    
 
 

 
 
   C	b* b* b*  b b b bP	 "N!M4L!M!M!M         D   $% % % %@       .2  2 2 2 2& & & &z  > #&  & & & &CE  E E E E '  	' ' ' ' ' 'T1 1 1 1      $6 6 6 6 6 6H    J   
",M&M@jkk",M,L@ghh", M*K@z{{", M+K@vww	",
 M.NOO", M(M@|}}", M$&8  AM  N  N", M(L  AA  B  B", M,$9@jkk", M)$4@uvv", M-$8@uvv", M-N@tuu", M($6@xyy", M%'>  CS  T  T", M*J@rss",  M%E@bcc!"," M%L@bcc#",$ M-$=@pqq%",& M"$=@pqq'",( M)$7?z{{)",* M)I@]^^+",, M/$5@{||-",. M,$5@eff/",0 M)$?@z{{1",2 M.N@xyy3",4 M'J@jkk5",6 M%K@dee7",8 M*K@^__9",: M.N@rss;",< M-M@stt=",> M)M  AA  B  B?",@ M/O  AX  Y  YA",B M,$7@STTC",  " " " "J BA-@AAA .  J	5J
EJ EJ U	J
 iJ iJ YJ IJ -J J hJ XJ J MJ J  !J" ##J J$ I%J& 9'J( )J* w+J, -J. /J0 \1J2 ,3J4 o5J6 o7J8 _9J: k;J< ;=J> ?J@ AJB 
>CJD 	-EJ J JF }GJH IJJ lKJL MJN JOJP QJR JSJT UJV iWJX IYJZ Y[J\ <]J^ %_J` 'aJb 	-cJd MeJf }gJ J Jh HiJj 8kJl !mJn "oJp 'qJr %sJt 
9uJv 9wJx iyJz i{J| E}J~ EJ@ EAJB 
8CJD (EJF HGJH IJ JJ "SJ J J Z' ' ' '      4 A  A A A A A AH (- T T T T T T
2 2 2 2$    E  E E E E E EP 38 T T T T T T 8: 9 9 9 9   6 	; ; ; ; ;~ /0
  0 0 0 0 0 0h /  / / / / / /d7 7 7 7
	 	 	 	 FK      : C  	c

 
 
"
"##$X     ) ) ) )X!( !( !( !(H
 
 
 
   % % % % % %2/ / / /    "	???  
- - - -`0 0 0 0f$ $ $ $N   69 9 9 9F F F F&/     
Q 
Q 
Q 
Q,   Q Q Q Q
& & & &( ( ( ($7 7 7 7P )2	 3 3 3 ) )     &" " " "J JO | | | | | |~E E E E EP   
 
 
 
$   < 58         L *,  + + + +%(  ( ( ( (! " " " " "J           ""/ / / / /f ""    @ ""    0 B! B! B! B! B!P "	    BF F F F F$L$$ $ 	$
 i$ 9$ 9$ X$ -$ $ l$ $ $ l$ l$   !2!$" "#6#$$ "3#6"4 ),*,*!2#6#4#6"4G$ $ $ P /3!    $ /3!	& & & & & &R   @ @ @ @( /3!	& & & & & &b% !   :
 
 
 
   J /3!	)O )O )O )O )O )O^ "	K K K K K\    B "	a a a a a(  @ @ @ @ 49      6    ""?  	? ? ? ? ? ?L """W W W W W W W WrG   