
    )jP                   ^   U d Z ddlmZ ddlZddlZddlmZ ddlmZm	Z	m
Z
 ddlmZmZmZmZmZ ddlmZ ddlmZmZmZmZmZ  ej        e          Zd	Z ej        d
ej                  ZdudZ dvdZ! G d de	          Z"i d e"dd          d e"dd          d e"dd          d e"dd          d e"dd          d e"dd          d e"dd          d  e"dd           d! e"dd!          d" e"d#d"          d$ e"d$d%          d& e"d'd&          d( e"d)d(          d* e"d*d*          d+ e"d+d+          d, e"d-d,          d. e"d/d.           e"d0d1           e"d2d3           e"d4d5           e"d6d7          d8Z#d9e$d:<    G d; d<e	          Z%i Z&d=e$d><   i Z'd=e$d?<   dwd@Z(dxdBZ)e G dC dD                      Z*dydGZ+dzdKZ,d{dOZ-	 	 	 d|d}dVZ.	 d~ddYZ/	 	 	 	 	 dddcZ0	 	 	 	 	 	 dddjZ1ddl2Z3 e3j4                    Z5ddlZ6	 	 	 	 ddddmdPdnddsZ7	 	 	 	 	 	 dddtZ8dS )u  Shared model-switching logic for CLI and gateway /model commands.

Both the CLI (cli.py) and gateway (gateway/run.py) /model handlers
share the same core pipeline:

  parse flags -> alias resolution -> provider resolution ->
  credential resolution -> normalize model name ->
  metadata lookup -> build result

This module ties together the foundation layers:

- ``agent.models_dev``            -- models.dev catalog, ModelInfo, ProviderInfo
- ``hermes_cli.providers``        -- canonical provider identity + overlays
- ``hermes_cli.model_normalize``  -- per-provider name formatting

Provider switching uses the ``--provider`` flag exclusively.
No colon-based ``provider:model`` syntax — colons are reserved for
OpenRouter variant suffixes (``:free``, ``:extended``, ``:fast``).
    )annotationsN)	dataclass)List
NamedTupleOptional)custom_provider_slugdetermine_api_mode	get_labelis_aggregatorresolve_provider_full)normalize_model_for_provider)ModelCapabilities	ModelInfoget_model_capabilitiesget_model_infolist_provider_modelszNous Research Hermes 3 & 4 models are NOT agentic and are not designed for use with Hermes Agent. They lack the tool-calling capabilities required for agent workflows. Consider using an agentic model instead (Claude, GPT, Gemini, DeepSeek, etc.).z&(?:^|[/:])hermes[-_ ]?[34](?:[-_.:]|$)
model_namestrreturnboolc                X    | sdS t          t                              |                     S )zReturn True if *model_name* is a real Nous Hermes 3/4 chat model.

    Used to decide whether to surface the non-agentic warning at startup.
    Callers in :mod:`cli.py` and here should go through this single helper
    so the two sites don't drift.
    F)r   _NOUS_HERMES_NON_AGENTIC_REsearchr   s    >/home/wildlama/.hermes/hermes-agent/hermes_cli/model_switch.pyis_nous_hermes_non_agenticr   K   s.      u+22:>>???    c                2    t          |           rt          S dS )zHReturn a warning string if *model_name* is a Nous Hermes 3/4 chat model. )r   _HERMES_MODEL_WARNINGr   s    r   _check_hermes_model_warningr!   W   s    !*-- %$$2r   c                  (    e Zd ZU dZded<   ded<   dS )ModelIdentityz:Vendor slug and family prefix used for catalog resolution.r   vendorfamilyN__name__
__module____qualname____doc____annotations__ r   r   r#   r#   c   s(         DDKKKKKKKKr   r#   sonnet	anthropiczclaude-sonnetopuszclaude-opushaikuzclaude-haikuclaudegpt5openaizgpt-5gptcodexo3o4geminigoogledeepseekzdeepseek-chatgrokzx-aillamaz
meta-llamaqwenminimaxnemotronnvidiakimi
moonshotaizz-aiglmstepfunstepxiaomimimozarcee-aitrinity)rC   rE   rG   rH   zdict[str, ModelIdentity]MODEL_ALIASESc                  2    e Zd ZU dZded<   ded<   ded<   dS )DirectAliasz5Exact model mapping that bypasses catalog resolution.r   modelproviderbase_urlNr&   r,   r   r   rK   rK      s1         ??JJJMMMMMMMMr   rK   dict[str, DirectAlias]_BUILTIN_DIRECT_ALIASESDIRECT_ALIASESc                    t          t                    } 	 ddlm}  |            }|                    d          }t          |t                     r|                                D ]\  }}t          |t                     s|                    dd          }|                    dd          }|                    dd          }|r9t          |||	          | |                                	                                <   |                    di           }	t          |	t                     r |	                    d
          }
t          |
t                     r|	                    dd          }|
                                D ]\  }}t          |t                    r|                                s/|                                	                                }|| v rZ|                                }d|v r|                    dd          \  }}n|}|}t          |                                |                                p|d	          | |<   n# t          $ r Y nw xY w| S )a  Load direct aliases from config.yaml ``model_aliases:`` section.

    Config format::

        model_aliases:
          qwen:
            model: "qwen3.5:397b"
            provider: custom
            base_url: "https://ollama.com/v1"
          minimax:
            model: "minimax-m2.7"
            provider: custom
            base_url: "https://ollama.com/v1"

    Also reads ``model.aliases`` (set by ``hermes config set model.aliases.xxx``)
    and converts simple string entries (``ds-flash: deepseek/deepseek-v4-flash``)
    into DirectAlias objects.  The provider is parsed from the ``provider/``
    prefix in the value; if no slash, the current provider is used.
    r   )load_configmodel_aliasesrL   r   rM   customrN   )rL   rM   rN   aliases/   )dictrP   hermes_cli.configrS   get
isinstanceitemsrK   striplowerr   split	Exception)mergedrS   cfguser_aliasesnameentryrL   rM   rN   model_sectionsimple_aliasescurrent_providervaluekeyvals                  r   _load_direct_aliasesrm      si   ( )**F*111111kmm ww//lD)) 
	+1133 	 	e!%.. 		'2.. 99Z:: 99Z44 3>#h4 4 4F4::<<--//0
 ,,mT** 	*..y99N.$// #0#4#4Z#D#D #1#7#7#9#9  KD%%eS11 ! ! **,,,,..Cf}} ++--Cczz*-))C*;*;%%#3 #"-#kkmm!)!1!1!E5E!## # #F3KK
    Ms   H3I
 

IINonec                 d    t           s(t                               t                                 dS dS )u5  Lazy-load direct aliases on first use.

    Mutates the existing DIRECT_ALIASES dict in place rather than rebinding
    the module attribute. This keeps `from hermes_cli.model_switch import
    DIRECT_ALIASES` references valid in callers — rebinding would leave them
    pointing at a stale empty dict.
    N)rQ   updaterm   r,   r   r   _ensure_direct_aliasesrq      s7      6244555556 6r   c                      e Zd ZU dZded<   dZded<   dZded<   dZded	<   dZded
<   dZ	ded<   dZ
ded<   dZded<   dZded<   dZded<   dZded<   dZded<   dZded<   dZded<   dS )ModelSwitchResultz!Result of a model switch attempt.r   successr   r   	new_modeltarget_providerFprovider_changedapi_keyrN   api_modeerror_messagewarning_messageprovider_labelresolved_via_aliasNzOptional[ModelCapabilities]capabilitiesOptional[ModelInfo]
model_info	is_global)r'   r(   r)   r*   r+   ru   rv   rw   rx   rN   ry   rz   r{   r|   r}   r~   r   r   r,   r   r   rs   rs     s         ++MMMIO"""""GHHMON     04L4444&*J****Ir   rs   raw_argstuple[str, str, bool, bool]c                x   d}d}d}ddl }|                    dd|           } d| v r*d}|                     dd                                          } d	| v r*d}|                     d	d                                          } |                                 }d}g }|t          |          k     rf||         d
k    r'|dz   t          |          k     r||dz            }|dz  }n |                    ||                    |dz  }|t          |          k     fd                    |                                          }||||fS )ap  Parse --provider, --global, and --refresh flags from /model command args.

    Returns (model_input, explicit_provider, is_global, force_refresh).

    Examples::

        "sonnet"                         -> ("sonnet", "", False, False)
        "sonnet --global"                -> ("sonnet", "", True, False)
        "sonnet --provider anthropic"    -> ("sonnet", "anthropic", False, False)
        "--provider my-ollama"           -> ("", "my-ollama", False, False)
        "--refresh"                      -> ("", "", False, True)
        "sonnet --provider anthropic --global" -> ("sonnet", "anthropic", True, False)
    Fr   r   Nz3[\u2012\u2013\u2014\u2015](provider|global|refresh)z--\1z--globalTz	--refreshz
--providerrX       )resubreplacer^   r`   lenappendjoin)	r   r   explicit_providerforce_refresh_repartsifilteredmodel_inputs	            r   parse_model_flagsr     sd    IM wwMwX`aaH X	##J3399;; h##K44::<< NNE	AH
c%jj..8|##AE

(:(: %a!eFAAOOE!H%%%FA c%jj.. ((8$$**,,K*I}EEr   model_idprefixtuplec                   | t          |          d         }|                    d          r
|dd         }|                    d                                          }g }d}d}d}|D ]}|dk    r0|dv rd}|                                rd}||z  },|d	v r1d
}||z  }9|dk    r|                                r||z  }Z|dk    rTd|v rJ	 |                    t          |                    d                               n# t          $ r Y nw xY wd}||z  }|d	v rO|rI	 |                    t          |                    d                               n# t          $ r Y nw xY wd}d}|rI	 |                    t          |                    d                               n# t          $ r Y nw xY wd}d
}||z  }[|dk    r1|                                rd}|}{|dv rd}|d	v rd
}||z  }|d
k    r||z  }|rM|dk    rG	 |                    t          |                    d                               n# t          $ r Y nw xY w|	                                                    d	          }|                                }t          d |D                       }	ddddd}
|
                    |d          }|	||fz   S )uS  Sort key for model version preference.

    Extracts version numbers after the family prefix and returns a sort key
    that prefers higher versions.  Suffix tokens (``pro``, ``omni``, etc.)
    are used as tiebreakers, with common quality indicators ranked.

    Examples (with prefix ``"mimo"``)::

        mimo-v2.5-pro   → (-2.5, 0, 'pro')     # highest version wins
        mimo-v2.5       → (-2.5, 1, '')          # no suffix = lower than pro
        mimo-v2-pro     → (-2.0, 0, 'pro')
        mimo-v2-omni    → (-2.0, 1, 'omni')
        mimo-v2-flash   → (-2.0, 1, 'flash')
    NrW   rX   -r   startvV
in_versionz-_.	in_suffix.betweenc              3     K   | ]}| V  d S Nr,   ).0ns     r   	<genexpr>z"_model_sort_key.<locals>.<genexpr>  s$      ))q))))))r   r   )promaxplusturbo)r   
startswithlstripr^   isdigitr   floatrstrip
ValueErrorr_   r   r[   )r   r   restnums
suffix_bufstatenum_bufchsuffixversion_key_SUFFIX_RANKsuffix_ranks               r   _model_sort_keyr   Q  s     CKKLL!Ds ABBx;;s!!##D DJEG 6 6GTzz$ !$2u#b 

l""zz|| !2s'>>E'..*=*=$>$>????%    GGrMGGu !E'..*=*=$>$>????%    G! !E'..*=*=$>$>????%    G#b 

izz|| 	!$t$u#b 

k!!"J  5L((	KKgnnS11223333 	 	 	D	 %%e,,F\\^^F ))D)))))K QA>>L""61--K+v...sH   5D
DD#5E
E&%E&25F((
F54F55I 
II	raw_inputri   Optional[tuple[str, str, str]]c                   |                                                                  }t                       t                              |          }||j        |j        |fS t                                          D ]3\  }}|j                                        |k    r|j        |j        |fc S 4t                              |          }|dS |\  }}t          |          }		 ddl
m}
 |
                    |g           }|r<d |	D             }|D ]-}|                                |vr|	                    |           .n# t          $ r Y nw xY wt          |          }|r(| d|                                 fd|	D             }n"|                                fd|	D             }|sdS |r| d| n||                    fd	           ||d         |fS )
a  Resolve a short alias against the current provider's catalog.

    Looks up *raw_input* in :data:`MODEL_ALIASES`, then searches the
    current provider's models.dev catalog for the model whose ID starts
    with ``vendor/family`` (or just ``family`` for non-aggregator
    providers) and has the **highest version**.

    Returns:
        ``(provider, resolved_model_id, alias_name)`` if a match is
        found on the current provider, or ``None`` if the alias doesn't
        exist or no matching model is available.
    Nr   )_PROVIDER_MODELSc                6    h | ]}|                                 S r,   )r_   )r   ms     r   	<setcomp>z resolve_alias.<locals>.<setcomp>  s     ///!AGGII///r   rW   c                b    g | ]+}|                                                               )|,S r,   r_   r   )r   midr   s     r   
<listcomp>z!resolve_alias.<locals>.<listcomp>  sE     
 
 
yy{{%%f--

 
 
r   c                b    g | ]+}|                                                               )|,S r,   r   )r   r   family_lowers     r   r   z!resolve_alias.<locals>.<listcomp>  sE     
 
 
yy{{%%l33

 
 
r   c                $    t          |           S r   )r   )r   prefix_for_sorts    r   <lambda>zresolve_alias.<locals>.<lambda>  s    q/BB r   rk   )r^   r_   rq   rQ   r[   rM   rL   r]   rI   r   hermes_cli.modelsr   r   ra   r   sort)r   ri   rk   direct
alias_namedaidentityr$   r%   catalogr   staticseenr   
aggregatormatchesr   r   r   s                   @@@r   resolve_aliasr     sz     //


!
!
#
#C $$Fs33
 )..00 7 7
B8>>s""K:6666 #   %%HtNFF
 ##344G	666666!%%&6;; 	&//w///D & &7799D((NN1%%%    /00J 
%%V%%++--
 
 
 
"
 
 

 ||~~
 
 
 
"
 
 

  t /9D**&***fOLLBBBBLCCCgaj#..s   #AD> >
E
Er   user_providersrY   custom_providerslist | None	list[str]c                f    	 t          | ||d          }d |D             S # t          $ r g cY S w xY w)u   Return slugs of providers that have credentials.

    Uses ``list_authenticated_providers()`` which is backed by the models.dev
    in-memory cache (1 hr TTL) — no extra network cost.
    r   )ri   r   r   
max_modelsc                    g | ]
}|d          S )slugr,   )r   ps     r   r   z4get_authenticated_provider_slugs.<locals>.<listcomp>  s    ---a&	---r   )list_authenticated_providersra   )ri   r   r   	providerss       r    get_authenticated_provider_slugsr   	  sa    	0-)-	
 
 
	 .-9----   			s   ! 00r,   authenticated_providersc                D    |pd}|D ]}t          | |          }||c S dS )zTry to resolve an alias on the user's authenticated providers.

    Falls back to ``("openrouter", "nous")`` only when no authenticated
    providers are supplied (backwards compat for non-interactive callers).
    )
openrouternousN)r   )r   r   r   rM   results        r   _resolve_alias_fallbackr     sF     (A+AI  y(33MMM 4r   rL   rM   rN   rx   r   r   config_context_length
int | NoneOptional[int]c                    	 ddl m}  || |pd|pd|pd||          }|rt          |          S n# t          $ r Y nw xY w||j        rt          |j                  S dS )u	  Resolve the context length to show in /model output.

    models.dev reports per-vendor context (e.g. gpt-5.5 = 1.05M on openai)
    but provider-enforced limits can be lower (e.g. Codex OAuth caps the
    same slug at 272k). The authoritative source is
    ``agent.model_metadata.get_model_context_length`` which already knows
    about Codex OAuth, Copilot, Nous, and falls back to models.dev for the
    rest.

    When ``custom_providers`` is provided, per-model ``context_length``
    overrides from ``custom_providers[].models.<id>.context_length`` are
    honored — this closes #15779 where ``/model`` switch ignored user-set
    overrides.

    Prefer the provider-aware value; fall back to ``model_info.context_window``
    only if the resolver returns nothing.
    r   )get_model_context_lengthr   N)rN   rx   rM   r   r   )agent.model_metadatar   intra   context_window)	rL   rM   rN   rx   r   r   r   r   ctxs	            r   resolve_display_context_lengthr   0  s    4AAAAAA&&^Mr%-"7
 
 
  	s88O	   *";:,---4s   -1 
>>Fcurrent_modelcurrent_base_urlcurrent_api_keyr   r   c	                  LM ddl m}	m}
m}m} ddlm} d}|                                 M|}|rt          |||          }|[d| d}	 ddl	m
}  |            }|r|d	z  }|dd
         D ]}|d|j         z  }n# t          $ r Y nw xY wt          d||          S |j        }ddl m} ddlm} |                                                                L|                    L          }|r||k    rz|Lk    rt||v rpt)          |||          }||vrZLfd|D             }|rdd                    |           dnd}t          d||j        |dL dt/          |           d|           S Msr|j        rGddlm}  ||j                  }|r|MnPt          d||j        |d|j         d|j         d|           S t          d||j        |d|j         d|           S t5          M|          }||\  }M}nMt5          | |          }|%|\  }M}t6                              d|M|           nL|                                                                 }|t:          v r{t)          |||          } t=          | |           }!|!$|!\  }M}t6                              d|M|           nt:          |         }"t          d|d | d!|"j         d"|"j          d#          S | !                    d$          }#|#dk    rd"| vrtE          |          rt| d|#                                                                         }$| |#d%z   d                                         }%|$r%|%r#|$ d"|% Mt6                              d&| M           d}&tE          |          r|stG          |          }'|'rwM                                }(|'D ] })|)                                |(k    r|)Md'}& nA!|'D ]=})d"|)v r7|)$                    d"d%          \  }}*|*                                |(k    r|)Md'}& n>|pd}+|d(v pd)|+v pd*|+v },||k    r|,s|s|&s |
M|          }|r|\  }M||k    }-t/          |          }.|%                    d+          rt          |||          }/|/|/j        }.|}0|}1d}2|-s|rddl&}3d}4|rF|rDdd,lm'}5  |5|                                                                |          }4|4 |5||          }4|4|4j        r|pi                     |                                                                          p|pi                     |          pi }6tQ          |6                    d-d          pd                                          }7|7%                    d.          rJ|7)                    d/          r5|3j*                            |7d0d1         d                                          }7|7sftQ          |6                    d2d          pd                                          }8|8r-|3j*                            |8d                                          }7	  |||7pd|4j        M3          }9|9                    d-d          p|7}0|9                    d4d          p|4j        }1|9                    d5d          }2n# t          $ r |7}0|4j        }1d}2Y nw xY w	  ||M6          }9|9                    d-d          }0|9                    d4d          }1|9                    d5d          }2n# t          $ r$}:t          d||.|d7|. d8|:           cY d}:~:S d}:~:ww xY w	  ||M6          }9|9                    d-d          }0|9                    d4d          }1|9                    d5d          }2n# t          $ r Y nw xY w|r>tW                       tX                              |          };|;|;j        r|;j        }1d}2|0sd9}0t[          M|          M	  |M||0|1|2pd:          }<n$# t          $ r}:dddd;M d<|: d=}<Y d}:~:nd}:~:ww xY w|<                    d>          sd}=|rr|.                                D ]]\  }>}?|>|k    rR|?                    d?i           }@M|@v rd'}= n5t_          |@t`                    rtc          Mfd@|@D                       rd'}= n^|=s|rt_          |t`                    r|D ]}At_          |Atd                    s|A                    dAd          }B|Brd+|B nd}C|A                    d4d          }D|C|k    s|D|1k    rS|A                    dBd          }E|A                    d?i           }FM|Ek    rd'}= nt_          |Ftd                    rM|Fv rd'}= n|=rd'd'd|<                    dCd          d=}<n+|<                    dCdD          }Gt          dM||.||GE          S |<                    dF          r|<dF         M|dGv r |	M|0H          }2|dIv r ||M          }2|2stg          ||1          }2|2dJk    r1|dKv r-t_          |1tP                    r|1rti          j5        dLd|1          }1tm          |M          }Hto          |M          }Ig }J|<                    dC          r|J8                    |<dC                    ts          M          }K|Kr|J8                    |K           t          d'M||-|0|1|2|JrdM                    |J          nd|.||H|I|N          S )Oa  Core model-switching pipeline shared between CLI and gateway.

    Resolution chain:

      If --provider given:
        a. Resolve provider via resolve_provider_full()
        b. Resolve credentials
        c. If model given, resolve alias on target provider or use as-is
        d. If no model, auto-detect from endpoint

      If no --provider:
        a. Try alias resolution on current provider
        b. If alias exists but not on current provider -> fallback
        c. On aggregator, try vendor/model slug conversion
        d. Aggregator catalog search
        e. detect_provider_for_model() as last resort
        f. Resolve credentials
        g. Normalize model name for target provider

      Finally:
        h. Get full model metadata from models.dev
        i. Build result

    Args:
        raw_input: The model name (after flag parsing).
        current_provider: The currently active provider.
        current_model: The currently active model name.
        current_base_url: The currently active base URL.
        current_api_key: The currently active API key.
        is_global: Whether to persist the switch.
        explicit_provider: From --provider flag (empty = no explicit provider).
        user_providers: The ``providers:`` dict from config.yaml (for user endpoints).
        custom_providers: The ``custom_providers:`` list from config.yaml.

    Returns:
        ModelSwitchResult with all information the caller needs.
    r   )copilot_model_api_modedetect_provider_for_modelvalidate_requested_modelopencode_model_api_mode)resolve_runtime_providerr   NzUnknown provider 'z`'. Check 'hermes model' for available providers, or define it in config.yaml under 'providers:'.)validate_config_structureu1   

Run 'hermes doctor' — config issues detected:   u   
  • F)rt   r   rz   _AGGREGATOR_PROVIDERSALIASES)ri   r   r   c                J    g | ]}|                               r|k    | S r,   )r   )r   s_explicit_norms     r   r   z switch_model.<locals>.<listcomp>  sB          ||N33 89^8K8K 8K8K8Kr   z Did you mean: z, ?z
Provider 'z"' is an alias that routes through z&, which has no credentials configured.)rt   rv   r|   r   rz   )_auto_detect_local_modelzNo model detected on z (z@). Specify the model explicitly: /model <model-name> --provider zN' has no base URL configured. Specify a model: /model <model-name> --provider zAlias '%s' resolved to %s on %sz,Alias '%s' resolved via fallback to %s on %szAlias 'z
' maps to rW   z] but no matching model was found in any provider catalog. Try specifying the full model name.:rX   z3Converted vendor:model '%s' to aggregator slug '%s'T>   localrU   	localhostz	127.0.0.1zcustom:)resolve_user_providerrx   z${}r   key_env)	requestedexplicit_api_keyexplicit_base_urltarget_modelrN   ry   )r  r  z,Could not resolve credentials for provider 'z': zno-key-required)rx   rN   ry   zCould not validate `z`: )acceptedpersist
recognizedmessager  modelsc              3  t   K   | ]2}t          |t                    |                    d           k    V  3dS )re   N)r\   rY   r[   )r   r   ru   s     r   r   zswitch_model.<locals>.<genexpr>  sD      eeaQ[\]_cQdQdequuV}}	9eeeeeer   re   rL   r  zInvalid model)rt   ru   rv   r|   r   rz   corrected_model>   github-copilotcopilot)rx   >   opencodeopencode-goopencode-zenanthropic_messages>   r  r  z/v1/?$z | )rt   ru   rv   rw   rx   rN   ry   r{   r|   r}   r~   r   r   ):r   r   r   r   r   hermes_cli.runtime_providerr   r^   r   rZ   r   r  ra   rs   idr   hermes_cli.providersr  r_   r[   r   r   re   r
   rN   r  r   loggerdebugrI   r   r$   r%   findr   r   r`   r   osr
  r   endswithenvironrq   rQ   r   r]   r\   listanyrY   r	   r   r   r   r   r   r!   )Nr   ri   r   r   r   r   r   r   r   r   r   r   r   r   resolved_aliasrv   pdef_switch_errr   _cfg_issues_ci_AGG_PROVIDERS_PROVIDER_ALIAS_TABLE_alias_target_authed_suggestions_hintr  detectedalias_result_rk   authedfallback_resultr   	colon_posleftrightresolved_in_current_catalogr   new_model_lowerr   bare_base	is_customrw   r|   custom_pdefrx   rN   ry   r%  
_user_pdef_ruser_ucfg_ukey_kenvruntimee_da
validationoverrider   rc   
cfg_modelsrf   
entry_name
entry_slug	entry_urlentry_modelentry_modelsmsgr~   r   warningshermes_warnr  ru   sN                                                                               @@r   switch_modelrV  a  s   `            EDDDDDN!!I&O
  L6$
 

 <6%6 6 6 6 GGGGGG7799 @#XXK*2A2 @ @#'?#+'?'??   $#)    ' 	NMMMMMIIIIII*002288::-11.AA	00>11>116!1-!1  G
 g--       &      $,@dii&=&=@@@@)+  )!$3#'9'A^ A A#,_#=#=A A9>A A
 
 
 
  	} PPPPPP33DMBB  (II, %(7'+y"+pDI p p p p\mp p	 	 	 	 )!$3#'9'_TY _ _K\_ _	 	 	 	 %Y@@#+7(Ay. %Y0@AA#9E6OYLL1	?    //##))++Cm##9%5#1%5  
 #:)V"L"L".AP>OYLLF&	?   
  -S1H, %"+Cc C CX_ C Cx C C C	    &NN3//	q==S	%9%9mL\>]>]%9$ZiZ06688>>@@D%i!mnn5;;==E  '+$5$5e$5$5	Q%y   ',#)) 	&. 	&*?;;G &"+//"3"3" & &Cyy{{o55$'	6:3 6
  ' & &#::&)iiQ&7&7GAt#zz||>>,/	>B ; % !&B$(;; 
5 8K5$8 	
 /// 0" 0 0 0
 10<LMMH 6-5* '*:://N!!),, .+
 

 "(-N GHH G, G			 
 	E 	ELLLLLL 1 7 7 9 9 ? ? A A>RRJ!#VO^DD
!j&9!#)r../@/F/F/H/H/N/N/P/PQQ E"(b--o>>EBD 		)R006B77==??E%% @%..*=*= @
uQrT{B77==?? >EIIi44:;;AACC >JNN5"55;;==E22-%*]d&0&9!*	   "++i44=";;z266M*:M";;z266   %.
22-!*   "++i44";;z266";;z266 
 
 
(!$3#1'3*3 3/03 3	 	 	 	 	 	 	 	 	
	..*&  G kk)R00G{{:r22H{{:r22HH 	 	 	D	  ,     00?s|?|HH ,+ -YHHI
--%
 
 


  
 
 
?i??A??	
 







 >>*%% / 	"+1133 " "	c?**!$2!6!6J J..#'!*d33 "eeee:eeeee "'+H!E  	, 	<Ld1S1S 	)  !%.. "YYvr22
7AI3z333r
!IIj"55	00I4I4I"'))GR"8"8K#(99Xr#:#:L K//#'!,55 )|:S:S#' 	&*t5]g]k]kluwy]z]z{{JJ..O<<C$# /-#!    ~~'(( 201	 777)))WEEE EEE**?IFF  A%ox@@ 	(((>>>x%% ? ? 6)R22 */9EEL  ;;J H~~i   /
9-...-i88K %$$$ ')08@

8,,,b%)!   so   
1A< <
B	B	A!Z& &Z>=Z>A\ 
] \;5] ;] A^ 
^! ^!5` 
`)`$$`)Optional['_threading.Thread']c                     t                                           rdS t                                            dd} t          j        | dd          }|                                 |S )	u  Warm the provider-models disk cache in a background daemon thread.

    The no-args ``/model`` picker calls ``list_authenticated_providers()``,
    which fetches each authenticated provider's live ``/v1/models`` list on a
    cold/stale cache. Those fetches are independent HTTP round-trips but run
    serially, so the first ``/model`` open in a session (or any open after the
    1h cache TTL expires) blocks ~1-2s on the user's critical path.

    This pre-warms that exact path off-thread during idle session time: it
    runs ``list_authenticated_providers()`` once, which populates
    ``provider_models_cache.json`` for every authed provider. By the time the
    user types ``/model``, the picker hits the warm disk cache and renders in
    ~100ms.

    Fire-and-forget. Process-level Event guard ensures it runs at most once.
    Fully exception-isolated — a slow or offline provider can never affect the
    session. Returns the spawned thread (for tests) or None if already warmed.
    Nr   rn   c                     	 ddl m}   |             }t          |j        |j        |j        |j        |j        d           d S # t          $ r  t          
                    dd           Y d S w xY w)Nr   )load_picker_context2   )ri   r   r   r   r   r   zpicker cache prewarm failedT)exc_info)hermes_cli.inventoryrZ  r   ri   r   r   r   r   ra   r"  r#  )rZ  r   s     r   _warmz)prewarm_picker_cache_async.<locals>._warm  s    	G@@@@@@%%''C )!$!5!$!5!/"1!$!5       	G 	G 	GLL6LFFFFFF	Gs   >A &A,+A,Tzpicker-cache-prewarm)targetdaemonre   r   rn   )_picker_prewarm_doneis_setset
_threadingThreadr   )r^  ts     r   prewarm_picker_cache_asyncrh  h  ss    & ""$$ tG G G G( 	t:PQQQAGGIIIHr      )force_fresh_nous_tierr   r   rj  r   r   
List[dict]c               ,,   tuvwx ddl xddlm}m}m}	 ddlm}
 ddlm}m	}m
}m}m}m} g }t                      }t                      }t                      td^d	wd_twxfd}d`xfdvdav fd} |            }t          |          }d |D             |d<    |            |d<   d|vrddlm}  |            |d<   d|vrxj                            d          sDxj                            d          s*                                                                 dk    rddlm} ddlm}                                                                  dk    }xj                            d          p	|r|r|ndpd}	  |xj                            dd          |d          }n# |$ r g }Y nw xY w|s|r|r|g}||d<   ddlm} ddlm} |                                D ]\  } }!|                    |           }"|"r|"| k    r|"|v r(|!|v r-|                    |!          }#t7          |#t                    sX|
                    |           }$|$r|$j        d k    r{|$r|$j        rt=          |$j                  }%n,|#                    d!g           }%t7          |%t<                    st?          xfd"|%D                       }&|&sO	 dd#lm }'  |'            }(|(r+|(                    d$i                               |           rd%}&n# tB          $ r Y nw xY w|&s5 ||           })|)s&|                    | g           })| |v r || |)          })tE          |)          }*|)d|         }+| }, |	|!          }-|-r|-j#        n|!}.|$                    |,|.|, k    p|! k    d&|+|*d'd(           |%                    |,                                           |%                    |!            ||,           	dd)lm&}/ ddlm}0 d* |                                D             }1|/                                D ]n\  }2}3|2                                |v r|1                    |2|2          }4|4                                |v rJd&}&|3j        d+k    r ||4          }&n'|3j'        r t?          xfd,|3j'        D                       }&|&sT|3j        d k    rI|2|4fD ]D}5|0                    |5          }6|6r+|6j        r$t?          xfd-|6j        D                       rd%}& nE|&sg	 dd#lm }'  |'            }(|(                    d.i           }7|(r
|2|7v s|4|7v rd%}&n3# tB          $ r&}8tP          )                    d/|2|8           Y d}8~8nd}8~8ww xY w|&s\	 dd0l*m+}9  |9|4          }:|:,                                rd%}&n3# tB          $ r&}8tP          )                    d1|4|8           Y d}8~8nd}8~8ww xY w|&s|4d2k    r	 dd3l-m.};m/}<  |<            }= |;            }>|=r|=                    d4          s|>r|>                    d4          rd%}&n2# tB          $ r%}8tP          )                    d5|8           Y d}8~8nd}8~8ww xY w|&s3|4d6v r ||4          })n|3j        d+k    r{	  ||4          }?|?r|?n+|                    |4g           p|                    |2g           })n;# tB          $ r0 |                    |4g           p|                    |2g           })Y nw xY w|4dk    r|                    dg           })	 dd7lm0}@m1}Am2}Bm3}C dd8lm4}D  |@d          pi }Ed}F	  |Dd          pi }G|G                    d9d          pd}Fn# tB          $ r d}FY nw xY w |A|:          r |B|)|E|F          \  })}Hn |C|)|E|F          \  })}HnY# tB          $ r Y nMw xY w ||4          })|)s<|                    |4g           p|                    |2g           })|4|v r ||4|)          })tE          |)          }*|)d|         }+|$                    |4tk          |4          |4 k    p|2 k    d&|+|*d;d(           |%                    |2                                           |%                    |4                                            ||4           p	 dd<lm6}I n# tn          $ r g }IY nw xY w|ID ]=}J|Jj8                                        |v r|0                    |Jj8                  }Kd&}L|Kr'|Kj        r t?          xfd=|Kj        D                       }L|LsE	 dd#lm }'  |'            }M|M                    d.i           }N|Mr|Jj8        |Nv rd%}Ln# tB          $ r Y nw xY w|Ls>	 dd0l*m+}9  |9|Jj8                  }O|O,                                rd%}Ln# tB          $ r Y nw xY w|Ls'|Kr%ts          |Kd>d          d+k    r ||Jj8                  }L|Ls|Krqts          |Kd>d          d+k    r\	  ||Jj8                  }?|?r|?n|                    |Jj8        g           }PnX# tB          $ r |                    |Jj8        g           }PY n1w xY w ||Jj8                  }P|Ps|                    |Jj8        g           }PtE          |P          }Q|Pd|         }R|$                    |Jj8        |Jj:        |Jj8         k    d&|R|Qd?d(           |%                    |Jj8                                                    ||Jj8                   ?t                      }S|rt7          |t                    r|                                D ]\  }T}Ut7          |Ut                    s|T                                |v r3|U                    d@d          p|T}.|U                    dAd          p-|U                    dBd          p|U                    dd          pd}V|U                    dCd          p|U                    dDd          }Wg }X|Wr|X$                    |W           |U                    dEg           }Yt7          |Yt                    r!|YD ]}Z|Zr|Z|Xvr|X$                    |Z           n5t7          |Yt<                    r |YD ]}Z|Zr|Z|Xvr|X$                    |Z           |Xs_tw          |V                                                                          }[dF|[v r(|                    dG          pg }\|\rt=          |\          }Xtw          |U                    d d          pd                                          }]|]shtw          |U                    dHd          pd                                          }^|^r-xj                            |^d                                          nd}]|U                    dId%          }_t7          |_tv                    r|_                                dJv}_|Vr,|]r*|_r(	 ddKlm<}`  |`|]|V          }a|ar|a}Xn# tB          $ r Y nw xY w|$                    |T|.|T k    d%|X|XrtE          |X          nddL|VdM           |%                    |T                                           |%                    t{          |.                                                     tw          |.                                                                          tw          |V                                          >                    dN                                          f}b|bd         r|bdO         r|S%                    |b           |rt7          |t<                    rddPl?m@}c  |c            }d|D ]}et7          |et                    s|e                    d@          pd                                }f|e                    dAd          p-|e                    dd          p|e                    dBd          pd                                >                    dN          }V|fr|Vs|e                    d           pd                                }g|e                    dH          pd                                }^|gp0|^r-xj                            |^d                                          nd}]tw          |e                    dQ          p|e                    dR          pd                                                                          }h|gr|gn|^rdS|^ nd}i|e                    dId%          }_t7          |_tv                    r|_                                dJv}_|V|i|hf}j|j|dvrZ|f}.dTD ]5}k|k|.v r/|.A                    |k          d                                         }. n6|.s|f}.t{          |.          },|,|.|V|]g |_dU|d|j<   n5|]r&|d|j                             d           s|]|d|j         d <   |_sd&|d|j         dI<   |e                    dD          pd                                }W|Wr1|W|d|j         dE         vr!|d|j         dE         $                    |W           |e                    dEi           }Yt7          |Yt                    r:|YD ]5}Z|Zr1|Z|d|j         dE         vr!|d|j         dE         $                    |Z           69t7          |Yt<                    r8|YD ]5}Z|Zr1|Z|d|j         dE         vr!|d|j         dE         $                    |Z           6t                      }ltw          |pd                                          >                    dN                                          ut          ufdV|dC                                D                       }m|dC                                D ]}n|ndW         }V|n                    d d          }]|nd
         },|,                                |v r|,                                |lvrV|,                                |lv rK|,}odX}p|o dY|p                                 |v r |pdOz  }p|o dY|p                                 |v  |o dY|p },|,|nd
<   tw          |nd@                                                                                   tw          |ndW                                                   >                    dN                                          f}q|qd         r|qdO         r|q|Sv rR|qdO         }r|rr|rtv rbt          |V          o-t          |]          p|ndE          o|n                    dId%          }s|sr=	 ddKlm<}`  |`|]|V          }a|ar|a|ndE<   tE          |a          |ndZ<   n# tB          $ r Y nw xY w|$                    |,|nd@         |, k    p  d[k    ot          u          o|ruk    o|mdOk    d%|ndE         tE          |ndE                   dL|ndW         dM           |%                    |,                                           |l%                    |,                                           |E                    d\ ]           |S )bu  Detect which providers have credentials and list their curated models.

    Uses the curated model lists from hermes_cli/models.py (OPENROUTER_MODELS,
    _PROVIDER_MODELS) — NOT the full models.dev catalog.  These are hand-picked
    agentic models that work well as agent backends.

    Returns a list of dicts, each with:
      - slug: str — the --provider value to use
      - name: str — display name
      - is_current: bool
      - is_user_defined: bool
      - models: list[str] — curated model IDs (up to max_models)
      - total_models: int — total curated count
      - source: str — "built-in", "models.dev", "user-config"

    Only includes providers that have API keys set or are user-defined endpoints.
    ``force_fresh_nous_tier`` bypasses the short Nous tier cache for explicit
    account-sensitive flows. UI picker opens should leave it false so they do
    not block on fresh Portal/account checks every time.
    r   N)PROVIDER_TO_MODELS_DEVfetch_models_devget_provider_infoPROVIDER_REGISTRY)OPENROUTER_MODELSr   _MODELS_DEV_PREFERRED_merge_with_models_devcached_provider_model_idsget_curated_nous_model_idsurlr   r   c                    t          | pd                                                              d                                          S )Nr   rW   r   r^   r   r_   )rw  s    r   	_norm_urlz/list_authenticated_providers.<locals>._norm_url  s8    39"~~##%%,,S1177999r   r   rn   c                H   	 ddl m} n# t          $ r Y dS w xY w|                    |           }|sdS d}t	          |dd          r"j                            |j        d          pd}|st	          |dd          pd} |          }|r                    |           dS dS )a	  Record the effective base URL for a built-in provider row.

        Prefers the live env-override (e.g. DASHSCOPE_BASE_URL) over the
        static inference_base_url so the dedup matches what a user typing
        that URL into custom_providers would actually hit.r   rp  Nr   base_url_env_varinference_base_url)hermes_cli.authrq  ra   r[   getattrr'  r|  add)r   _regpcfgrw  normed_builtin_endpointsrz  r%  s        r   _record_builtin_endpointz>list_authenticated_providers.<locals>._record_builtin_endpoint  s    	AAAAAAA 	 	 	FF	xx~~ 	F4+R00 	B*..!6;;ArC 	@$ 4b99?RC3 	+""6*****	+ 	+s   
 
r   c                 P    j                             dd                                          rdS  j                             dd                                          r/ j                             dd                                          rdS t           fddD                       S )aT  Return True when explicit AWS auth config is present.

        This intentionally avoids botocore's full credential chain. Provider
        picker/model-switch discovery can run for non-Bedrock providers, and
        botocore may otherwise probe EC2 IMDS (169.254.169.254) on local
        machines before returning no credentials.
        AWS_BEARER_TOKEN_BEDROCKr   TAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYc              3  r   K   | ]1}j                             |d                                           V  2dS )r   N)r'  r[   r^   )r   re   r%  s     r   r   zQlist_authenticated_providers.<locals>._has_fast_aws_sdk_signal.<locals>.<genexpr>  sS       
 
 JNN4$$**,,
 
 
 
 
 
r   )AWS_PROFILE&AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"AWS_CONTAINER_CREDENTIALS_FULL_URIAWS_WEB_IDENTITY_TOKEN_FILE)r'  r[   r^   r)  )r%  s   r   _has_fast_aws_sdk_signalz>list_authenticated_providers.<locals>._has_fast_aws_sdk_signal  s     :>>4b99??AA 	4JNN.3399;;	
6;;AACC	 4 
 
 
 

 
 
 
 
 	
r   c                ^   t          | pd                                                                          }t          pd                                                                          }             rdS ||k    rdS 	 ddlm} t           |                      S # t          $ r Y dS w xY w)z@Credential check for AWS SDK providers in non-runtime discovery.r   TFr   )has_aws_credentials)r   r^   r_   agent.bedrock_adapterr  r   ra   )r   	slug_normcurrent_normr  r  ri   s       r   _has_aws_sdk_creds_for_listingzDlist_authenticated_providers.<locals>._has_aws_sdk_creds_for_listing  s    
OO))++1133	+1r2288::@@BB##%% 	4$$5	AAAAAA++--... 	 	 	55	s   B 
B,+B,c                    g | ]\  }}|S r,   r,   r   r   r7  s      r   r   z0list_authenticated_providers.<locals>.<listcomp>  s    AAAVS!SAAAr   r   r   zollama-cloud)fetch_ollama_cloud_modelslmstudio
LM_API_KEYLM_BASE_URL)fetch_lmstudio_models)	AuthErrorzhttp://127.0.0.1:1234/v1r   g      ?)rx   rN   timeoutr   r   rx   envc              3  L   K   | ]}j                             |          V  d S r   r'  r[   r   evr%  s     r   r   z/list_authenticated_providers.<locals>.<genexpr>e  s1      >>r
r**>>>>>>r   )_load_auth_storecredential_poolTFzbuilt-in)r   re   
is_currentis_user_definedr  total_modelssource)HERMES_OVERLAYSc                    i | ]\  }}||	S r,   r,   )r   kvs      r   
<dictcomp>z0list_authenticated_providers.<locals>.<dictcomp>  s    GGG1q!GGGr   aws_sdkc              3  L   K   | ]}j                             |          V  d S r   r  r  s     r   r   z/list_authenticated_providers.<locals>.<genexpr>  s1      PP2BJNN2..PPPPPPr   c              3  L   K   | ]}j                             |          V  d S r   r  r  s     r   r   z/list_authenticated_providers.<locals>.<genexpr>  s1      NN"2:>>"--NNNNNNr   r   z"Auth store check failed for %s: %s)	load_poolz'Credential pool check failed for %s: %sr.   )read_claude_code_credentialsread_hermes_oauth_credentialsaccessTokenz)Anthropic external creds check failed: %s>   copilot-acpopenai-codexr  )get_pricing_for_providercheck_nous_free_tier&union_with_portal_free_recommendations&union_with_portal_paid_recommendations)get_provider_auth_stateportal_base_url)force_freshhermes)CANONICAL_PROVIDERSc              3  L   K   | ]}j                             |          V  d S r   r  r  s     r   r   z/list_authenticated_providers.<locals>.<genexpr>>  s1      YYr
r 2 2YYYYYYr   	auth_type	canonicalre   rN   apidefault_modelrL   r  zapi.openai.comr3   r  discover_models>   0nofalse)fetch_api_modelszuser-config)r   re   r  r  r  r  r  api_urlrW   rX   )OrderedDictry   	transportzenv:)u   —z - )r   re   r  rx   r  r  c              3     K   | ]X}rTt          |d                                                                        d                                          k    TdV  YdS )r  rW   rX   Nry  )r   _grp_current_base_url_norms     r   r   z/list_authenticated_providers.<locals>.<genexpr>@  sz       ,
 ,
%,
 DO$$**,,33C88>>@@DZZZ  [ZZZ	,
 ,
r   r  r   r   r  rU   c                &    | d          | d          fS )Nr  r  r,   )rs    r   r   z.list_authenticated_providers.<locals>.<lambda>  s    AlO 3a6G5GH r   r   )rw  r   r   r   )r   r   r   rn   )r   r   )r   r   r   r   )Fr%  agent.models_devrm  rn  ro  r~  rq  r   rr  r   rs  rt  ru  rv  rd  rY   r  r'  r[   r^   r_   r  r  r   r!  r  r]   r\   r  api_key_env_varsr(  r)  r  ra   r   re   r   r  r  extra_env_varsr"  r#  agent.credential_poolr  has_credentialsagent.anthropic_adapterr  r  r  r  r  r  r  r
   r  ImportErrorr   r  labelr   r  r   r   collectionsr  r`   sumvaluesr   r   )yri   r   r   r   rj  r   r   rm  rn  _mdev_pinforq  rr  r   rs  rt  ru  rv  results
seen_slugsseen_mdev_idsr  r  datacuratedr  r  r  is_current_lmstudiolm_baseliver/  r0  	hermes_idmdev_idr1  pdatapconfigenv_vars	has_credsr  store	model_idstotaltopr   pinfodisplay_namer  _auth_registry_mdev_to_hermespidoverlayhermes_slug_keyr  providers_storeexcr  poolr  r  hermes_credscc_creds_ids_nous_pricing
_nous_free_union_free_union_paid_nous_state_pricing_portal_str7  _canon_provs_cp
_cp_config_cp_has_creds	_cp_store_cp_providers_store_cp_pool_cp_model_ids	_cp_total_cp_top_section3_emitted_pairsep_nameep_cfgr  r  models_listrM  r   	url_lowerfbrx   r  discoverr  live_models_pairr  groupsrf   raw_nameinline_api_keyry   credential_identity	group_keysep_section4_emitted_slugs_current_base_url_group_countgrp	base_slugr   	_pair_key_grp_url_normshould_prober  r  r  rz  r%  sy   `                                                                                                                   @@@@@r   r   r     s   < III         
 211111                GeeJM "ee: : : :+ + + + + + + +,
 
 
 
 
 
2       D %))9$:$:GAA/@AAAGL 1022GFOW$$??????";";"="=   

|$$ !(*
}(E(E !IYI_I_IaIaIgIgIiIimwIwIw;;;;;;------.4466<<>>*LJNN=)) *$7V<LV  RV*) 	
	((
|R88   DD
  	 	 	DDD	 	#+ 	# 	#!?D"
 JIIIIIEEEEEE4::<< P' P'	7 .11)<<	**// m##!!%&& 	
 $''	22  	w(I55 	w/ 	G455HHyy++Hh--  >>>>X>>>>>	 	<<<<<<((** %UYY'8"==AA)LL % $I    	 .-i88	 	IIr22I111229iHH	I$G$$%*7uzz "22QgAQ6Q$! 
 
 	 	 	 	tzz||$$$'"""  &&&& 544444CCCCCC
 HG(>(D(D(F(FGGGO'--// T. T.W99;;*$$ &))#s33*,, 		))66{CCII# 	QPPPP9OPPPPPI 	W.);;k*  %))$// D1 NNNN8MNNNNN $(	
  	MM<<<<<<((**"'))K"<"< %c_448V8V $I M M MA3LLLLLLLLM  	ZZ;;;;;; y--'')) % $I Z Z ZFUXYYYYYYYYZ  	O[K77O         =<>>7799  %\%5%5m%D%D %%!)m!<!<% $I O O OH#NNNNNNNNO 	DDD 21+>>II )++Q00==$(dDDw{{;/K/K/cw{{[^`bOcOc		 Q Q Q#KKR88PGKKR<P<P			QF""  FB//I            SRRRRR(=006B!%+f--3C!gg&7<<BGG  ! ! ! GGG!:*?@@@ M#.;y(G#L#LLIqq#.;y(G#L#LLIq    	 21+>>I O#KKR88PGKKR<P<P	"777 6 6{I N NII$k**%)99TSDT=T$!
 
 	 	 	 	syy{{###{((**+++  ----IIIIIII     ?+ ?+8>>z)) $''11
 	Z*5 	ZYYYYZ=XYYYYYM 	<<<<<<,,..	&/mmK&D&D# )-@!@!@$(M    	;;;;;;$9SX..++-- )$(M     	E 	E
KQS0T0TXa0a0a::38DDM 	  
	:'*k2>>)KK:00::(, K'++ch2K2K : : : 'CHb 9 9: 65ch??M  : 'CHb 9 9&&	,HI(&66$%!
 
 	 	 	 	sx~~''(((  **** $'55 V3*^T:: V3-3355 U	3 U	3OGVfd++  }}*,,!::fb11<WL
 

:r** ::eR((::eR(( 	  #JJ;;Vvzz'SU?V?VM K 2""=111
  Hb11J*d++ .# . .A .Qk11#**1---. J-- .# . .A .Qk11#**1---  /LL..006688	#y00 X..4"B /&*2hh &**Y339r::@@BBG QfjjB77=2>>DDFFAHP"*.."55;;===bzz"3T::H(C(( H#>>++3GG 7 x BBBBBB"2"27G"D"DK" 2&1    D NN$%)99#'%4? FK 0 0 0Q'"	 	 	 	 	 NN7==??+++NN/==CCEEFFFL!!''))//11G""$$++C006688E Qx 3E!H 3'++E222  F6J'7>> F6++++++ .9[]]% S	> S	>EeT** 		&))/R6688H		*b)) 99UB''99UB'' eggffSkk   7 #ii	228b??AANyy++1r88::G$ 7>F
w++11333B  		*%% 99[))  eggeegg	  ";*19&W&&&r   yy!2D99H(C(( H#>>++3GG "5x@I&&
  ()  Cl**'3'9'9#'>'>q'A'G'G'I'I + $ ,#+L+L99 (&& '/% %y!!  ;6)#4#8#8#C#C ;3:F9%i0   A;@F9%&78 #YYw//52<<>>M BfY6G6Q!Q!Qy!(+22=AAA8R00J*d++ ># > >A >QfY&7&AAAy)(3::1===> J-- ># > >A >QfY&7&AAAy)(3::1==='*uu!$%5%;!<!<!B!B!D!D!K!KC!P!P!V!V!X!X(+ ,
 ,
 ,
 ,
,
 ,
 ,
 )
 )
% ==?? `	6 `	6C)nGggi,,Gv;D zz||z))djjllBY.Y.Y
 zz||666 	"((Q((..00J>>FA #((Q((..00J>>#))a))"F CK  &&((..00C	N##))++22377==??I | 	! >U1U1U &aLM 2D!D!D6 W 5']]7#h-&75GG-t44 
  	BBBBBB"2"27G"D"DK" ?(3H.1+.>.>N+    DNNF"&66 $0 ;344;%)??; 6:#'h- #CM 2 2'y>     NN4::<<(((#''

5555 LLHHLIIINs'  9'F! !F+*F+?=K==
L
	L
2T99
U)U$$U)/'V
W!WWAX  
Y*Y

Y3;Z006[*)[*
!^,%]^]!^ ]!!0^
^^b b*)b*3e


ee,f


ff/h%h76h7w
w,+w,T	+AT5T5
AUUAUc                   ddl m} t          | |||||          }g }|D ]8}	t          |	                    dd                                                    }
|
dk    ry	  |            }d |D             }n3# t          $ r& t          |	                    dg                     }Y nw xY wt          |	          }	|d	|         |	d<   t          |          |	d
<   t          |	                    d                    }t          |	                    d                    o!t          |	                    d                    }|s|s#|                    |	           :|S )a  Interactive-picker variant of :func:`list_authenticated_providers`.

    Post-processes the base list so the ``/model`` picker (Telegram/Discord
    inline keyboards) only surfaces models that are actually callable in the
    current install:

    - OpenRouter's model list is replaced with the output of
      :func:`hermes_cli.models.fetch_openrouter_models`, which filters the
      curated ``OPENROUTER_MODELS`` snapshot against the live OpenRouter
      catalog.  IDs the live catalog no longer carries drop out, so the
      picker never offers a model the user can't call.
    - Provider rows whose model list ends up empty are dropped, except
      custom endpoints (``is_user_defined=True`` with an ``api_url``) where
      the user may supply their own model set through config.

    All other providers and metadata fields are passed through unchanged.
    The typed ``/model <name>`` path is unaffected -- only the interactive
    picker payload is narrowed.
    r   )fetch_openrouter_models)ri   r   r   r   r   r   r   r   r   c                    g | ]\  }}|S r,   r,   r  s      r   r   z)list_picker_providers.<locals>.<listcomp>  s    333FCC333r   r  Nr  r  r  )r   r(  r   r   r[   r_   ra   r(  rY   r   r   r   )ri   r   r   r   r   r   r(  r   r   r   r   r  live_ids
has_modelsis_custom_endpoints                  r   list_picker_providersr-    s   6 :99999,))%)#  I H  155$$%%++--<5..0033d333 5 5 5h 3 3445QA";J;/AhK #HAn!%%//**
!!%%(9":":;;VQUU9EUEU@V@V 	"4 	Os   A66-B&%B&)r   r   r   r   )r   r   r   r   )r   rO   ra  )r   r   r   r   )r   r   r   r   r   r   )r   r   ri   r   r   r   )r   NN)ri   r   r   rY   r   r   r   r   )r,   )r   r   r   r   r   r   )r   r   NNN)rL   r   rM   r   rN   r   rx   r   r   r   r   r   r   r   r   r   )r   r   Fr   NN)r   r   ri   r   r   r   r   r   r   r   r   r   r   r   r   rY   r   r   r   rs   )r   rW  )r   r   NN)ri   r   r   r   r   rY   r   r   rj  r   r   r   r   r   r   rk  )r   r   NNri  r   )ri   r   r   r   r   rY   r   r   r   r   r   r   r   rk  )9r*   
__future__r   loggingr   dataclassesr   typingr   r   r   r!  r   r	   r
   r   r   hermes_cli.model_normalizer   r  r   r   r   r   r   	getLoggerr'   r"  r    compile
IGNORECASEr   r   r!   r#   rI   r+   rK   rP   rQ   rm   rq   rs   r   r   r   r   r   r   rV  	threadingre  Eventrb  rh  r   r-  r,   r   r   <module>r8     s    ( # " " " " "  				 ! ! ! ! ! ! - - - - - - - - - -                                
	8	$	$-   )bj-M  	@ 	@ 	@ 	@       J   1+{O<<1+ {M::1+ {N;;	1+
 {H551+ x111+ 
x//1+ x111+ 	x..1+ 	x..1+ x221+$ z?;;%1+* vv..+1+0 |W5511+6 vv..71+< y)44=1+B x44C1+H |V44I1+N vu-- y&11 x00 z955a1+ 1+ 1+ 1 1 1 1x    *    35  4 4 4 4 *, + + + +@ @ @ @F	6 	6 	6 	6         *.F .F .F .Fjh/ h/ h/ h/VJ/ J/ J/ J/\ $(    0 *,    ( &*$((,* * * * *j $(x x x x xD    'z')) - - - -b $(	S #(S S S S S Sn $(9 9 9 9 9 9 9r   