
    Pmj'              
          U d Z ddlZddlZddlZddlZddlmZ ddlmZ ddl	m
Z
mZmZmZmZ ddlmZ ddlZ ej        e          ZdZdZd	Zi aeee
f         ed
<   daeed<   daeed<    ej                    Z ej                    Z da!e G d d                      Z"e G d d                      Z#i ddddddddddddddddddddddddd dd!d!d"d"d#d#d$d#i d%d&d'd(d)d*d+d+d,d-d.d/d0d0d1d2d2d2d3d3d4d3d5d5d6d6d7d7d8d8d9d9d:d:d;d<d=Z$eeef         ed><   dZ%eeeef                  ed?<   d@efdAZ&d@eee
f         fdBZ'd@ee         fdCZ(dDeee
f         d@dfdEZ)d@eee
f         fdFZ*dkdGZ+dDeee
f         dHed@dfdIZ,dJe-dHed@dfdKZ.dkdLZ/dkdMZ0	 dldNdOdPe1dQe1d@eee
f         fdRZ2dSedTed@ee3         fdUZ4dVeee
f         d@ee3         fdWZ5e G dX dY                      Z6dSed@eeee
f                  fdZZ7d[eee
f         dTed@eeee
f                  fd\Z8dSedTed@ee6         fd]Z9dSed@ee         fd^Z:ddl;Z; e;j<        d_e;j=                  Z>e;j?        ed`<    e@h da          ZAdSedbed@e1fdcZBdSed@ee         fddZCdbedeeee
f         dfed@e"fdgZDdfedeeee
f         d@e#fdhZEdNdOdfedQe1d@ee#         fdiZFdfedbed@ee"         fdjZGdS )mup  Models.dev registry integration — primary database for providers and models.

Fetches from https://models.dev/api.json — a community-maintained database
of 4000+ models across 109+ providers.  Provides:

- **Provider metadata**: name, base URL, env vars, documentation link
- **Model metadata**: context window, max output, cost/M tokens, capabilities
  (reasoning, tools, vision, PDF, audio), modalities, knowledge cutoff,
  open-weights flag, family grouping, deprecation status

Data resolution order:
  1. In-memory cache (fresh, or stale served immediately while a single
     background daemon thread refreshes)
  2. Disk cache (~/.hermes/models_dev_cache.json — any age; stale data is
     served rather than blocking callers on the network)
  3. Network fetch (https://models.dev/api.json) — only when no cache
     exists at all; failed refreshes back off for 5 minutes process-wide
Latency-sensitive callers (gateway route-identity checks) pass
``allow_network=False`` and never touch the network.

Other modules should import the dataclasses and query functions from here
rather than parsing the raw JSON themselves.
    N)	dataclass)Path)AnyDictListOptionalTuple)atomic_json_writezhttps://models.dev/api.jsoni  i,  _models_dev_cache_models_dev_cache_time_models_dev_retry_afterFc                      e Zd ZU dZeed<   eed<   eed<   eed<   dZeed<   dZeed<   dZ	eed	<   dZ
eed
<   dZeed<   dZeed<   dZeedf         ed<   dZeedf         ed<   dZeed<   dZeed<   dZee         ed<   dZeed<   dZeed<   dZee         ed<   dZee         ed<   dZeed<   dZeed<   dZeed<   dZeed<   d efd!Zd efd"Z d efd#Z!d efd$Z"d efd%Z#d efd&Z$dS )'	ModelInfoz1Full metadata for a single model from models.dev.idnamefamilyprovider_idF	reasoning	tool_call
attachmenttemperaturestructured_outputopen_weights .input_modalitiesoutput_modalitiesr   context_window
max_outputN	max_inputg        
cost_inputcost_outputcost_cache_readcost_cache_write knowledge_cutoffrelease_datestatusinterleavedreturnc                 .    | j         dk    p
| j        dk    S )Nr   )r    r!   selfs    6/home/thesage/.hermes/hermes-agent/agent/models_dev.pyhas_cost_datazModelInfo.has_cost_data^   s    ":d&6&::    c                 "    | j         pd| j        v S )Nimage)r   r   r+   s    r-   supports_visionzModelInfo.supports_visiona   s    B'T-B"BBr/   c                     d| j         v S )Npdfr   r+   s    r-   supports_pdfzModelInfo.supports_pdfd   s    ---r/   c                     d| j         v S )Naudior5   r+   s    r-   supports_audio_inputzModelInfo.supports_audio_inputg   s    $///r/   c                     |                                  sdS d| j        ddd| j        ddg}| j        |                    d| j        dd           d	                    |          S )
z<Human-readable cost string, e.g. '$3.00/M in, $15.00/M out'.unknown$z.2fz/M inz/M outNzcache read $z/M, )r.   r    r!   r"   appendjoin)r,   partss     r-   format_costzModelInfo.format_costj   s    !!## 	9/T_////1QT5E1Q1Q1Q1QR+LLD(<DDDDEEEyyr/   c                    g }| j         r|                    d           | j        r|                    d           |                                 r|                    d           |                                 r|                    d           |                                 r|                    d           | j        r|                    d           | j        r|                    d           |rd                    |          nd	S )
zBHuman-readable capabilities, e.g. 'reasoning, tools, vision, PDF'.r   toolsvisionPDFr8   zstructured outputzopen weightsr=   basic)	r   r>   r   r2   r6   r9   r   r   r?   )r,   capss     r-   format_capabilitieszModelInfo.format_capabilitiess   s   > 	%KK$$$> 	!KK   !! 	"KK!!! 	KK$$&& 	!KK   ! 	-KK+,,, 	(KK'''"&3tyyG3r/   )%__name__
__module____qualname____doc__str__annotations__r   boolr   r   r   r   r   r   r	   r   r   intr   r   r   r    floatr!   r"   r#   r%   r&   r'   r(   r   r.   r2   r6   r9   rA   rH   r   r/   r-   r   r   8   sE        ;;GGG
IIIKKK ItItJK#t###L$ )+eCHo***)+uS#X+++ NCJ#Ix}### JK'+OXe_+++(,huo,,, cL#FCK;t ; ; ; ;C C C C C.d . . . .0d 0 0 0 0 S        4S 4 4 4 4 4 4r/   r   c                   h    e Zd ZU dZeed<   eed<   eedf         ed<   eed<   dZeed<   d	Ze	ed
<   dS )ProviderInfoz-Full metadata for a provider from models.dev.r   r   .envapir$   docr   model_countN)
rI   rJ   rK   rL   rM   rN   r	   rV   rW   rP   r   r/   r-   rS   rS      sd         77GGG
III	sCx	HHHCMMMKr/   rS   
openrouternovitaz	novita-ai	anthropicopenaizopenai-codexzaikimizkimi-for-codingzkimi-codingmoonshotstepfunzkimi-coding-cnminimaxzminimax-oauthz
minimax-cndeepseekalibabaz
qwen-oauthcopilotzgithub-copilotz
ai-gatewayvercelzopencode-zenopencodezopencode-gokilocodekilo	fireworkszfireworks-aihuggingfacegeminigooglexaiz	xai-oauthxiaominvidiagroqmistral
togetherai
perplexitycohereollama-cloud)rs   rt   PROVIDER_TO_MODELS_DEV_MODELS_DEV_TO_PROVIDERr)   c                  (    ddl m}   |             dz  S )zReturn path to disk cache file.r   get_hermes_homezmodels_dev_cache.json)hermes_constantsry   rx   s    r-   _get_cache_pathr{      s(    000000?666r/   c                  ,   	 t                      } |                                 r=t          | d          5 }t          j        |          cddd           S # 1 swxY w Y   n2# t
          $ r%}t                              d|           Y d}~nd}~ww xY wi S )z%Load models.dev data from disk cache.zutf-8)encodingNz(Failed to load models.dev disk cache: %s)r{   existsopenjsonload	Exceptionloggerdebug)
cache_pathfes      r-   _load_disk_cacher      s    D$&&
 	$j7333 $qy||$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ D D D?CCCCCCCCDIs:   3A" A	A" AA" AA" "
B,BBc                  $   	 t                      } |                                 sdS |                                 j        }t	          j                    |z
  }|dk     rdS |S # t
          $ r&}t                              d|           Y d}~dS d}~ww xY w)u<  Return age (in seconds) of the disk cache file, or None if missing.

    Used by ``fetch_models_dev`` to short-circuit the network probe when
    a recent on-disk cache exists. Errors (missing file, permission
    denied, weird filesystem) all return None — callers fall through
    to the network fetch path.
    Nr   z(Failed to stat models.dev disk cache: %s)r{   r~   statst_mtimetimer   r   r   )r   mtimeager   s       r-   _disk_cache_age_secondsr      s    $&&
  "" 	4!!*ikkE!
 774
   ?CCCttttts"   "A 5A A 
B)B

Bdatac                     	 t                      }t          || dd           dS # t          $ r&}t                              d|           Y d}~dS d}~ww xY w)z.Save models.dev data to disk cache atomically.N),:)indent
separatorsz(Failed to save models.dev disk cache: %s)r{   r
   r   r   r   )r   r   r   s      r-   _save_disk_cacher      sz    D$&&
*d4JOOOOOO D D D?CCCCCCCCCDs   !% 
AAAc                      t          j        t          d          } |                                  |                                 }t          |t                    r|st          d          |S )zFetch the live models.dev registry without touching local caches.

    Raises on network errors and on an empty/invalid registry payload.
    )   
   )timeoutz0models.dev returned an empty or invalid registry)requestsgetMODELS_DEV_URLraise_for_statusr   
isinstancedict
ValueError)responser   s     r-   _fetch_models_dev_from_networkr      sf     |NG<<<H==??DdD!! M MKLLLKr/   c                  j    t          j                     t          z
  t          z   } | t          k    r| adS dS )a$  Give stale cache data a short in-memory grace before retrying refresh.

    Only ever moves the timestamp forward: if a background refresh completed
    between the caller's staleness check and this call, the fresh timestamp
    is preserved instead of being rewound to a 5-minute grace.
    N)r   _MODELS_DEV_CACHE_TTL_MODELS_DEV_RETRY_DELAYr   )
grace_times    r-   _mark_stale_cache_gracer     s;     447NNJ***!+ +*r/   wherec          
          t          |            | at          j                    adat
                              d|t          |           t          d | 	                                D                                  dS )aa  Persist a freshly fetched registry: disk + in-mem + clear backoff.

    Callers must hold ``_models_dev_fetch_lock`` so a failing refresh on one
    path can never stomp the state a succeeding refresh on the other path
    just committed (e.g. a failing background worker re-arming the backoff
    immediately after a successful ``force_refresh``).
    r   zARefreshed models.dev registry (%s): %d providers, %d total modelsc              3      K   | ]<}t          |t                    t          |                    d i                     V  =dS )modelsN)r   r   lenr   ).0ps     r-   	<genexpr>z#_commit_registry.<locals>.<genexpr>+  sG      SSz!T?R?RSCh##$$SSSSSSr/   N)
r   r   r   r   r   r   r   r   sumvalues)r   r   s     r-   _commit_registryr     s{     T!Y[[
LLKD		SSdkkmmSSSSS	    r/   excc                    t          j                     t          z   at                              d|t          |            dS )zRecord a failed refresh: arm the process-wide 5-minute backoff.

    Callers must hold ``_models_dev_fetch_lock`` (see ``_commit_registry``).
    z<models.dev refresh failed (%s); retry suppressed for %ds: %sN)r   r   r   r   r   )r   r   s     r-   _note_refresh_failurer   /  sB     #ikk,CC
LLF	    r/   c                     	 t                      } t          5  t          | d           ddd           n# 1 swxY w Y   nG# t          $ r:}t          5  t	          |d           ddd           n# 1 swxY w Y   Y d}~nd}~ww xY wt
          5  daddd           dS # 1 swxY w Y   dS # t
          5  daddd           w # 1 swxY w Y   w xY w)z3Best-effort refresh after serving stale cache data.
backgroundr   NF)r   _models_dev_fetch_lockr   r   r   _models_dev_refresh_lock_models_dev_refresh_in_flight)r   r   s     r-   _background_refresh_models_devr   >  s   	2-//# 	7 	7T6666	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 9 9 9# 	9 	9!!<8888	9 	9 	9 	9 	9 	9 	9 	9 	9 	9 	9 	9 	9 	9 	99 & 	2 	2,1)	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2% 	2 	2,1)	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2s   A 5A 9A 9A  B, 
BB A0$B 0A4	4B 7A4	8B ;B,  BB, BB#&B#,C4C7CCC
CCc                     t          j                     t          k     rdS t          5  t          r	 ddd           dS daddd           n# 1 swxY w Y   t	          j        t          dd          } 	 |                                  dS # t          $ rG}t          5  daddd           n# 1 swxY w Y   t          
                    d|           Y d}~dS d}~ww xY w)zStart one daemon refresh worker if none is already running.

    Honors the process-wide failure backoff: after a failed refresh,
    no new background worker is spawned until ``_models_dev_retry_after``.
    NTzmodels-dev-refresh)targetr   daemonFz-Failed to start models.dev refresh thread: %s)r   r   r   r   	threadingThreadr   startr   r   r   )threadr   s     r-   $_start_background_refresh_models_devr   M  s    y{{,,,	! - -( 	- - - - - - - - )-%- - - - - - - - - - - - - - - -!  F
I I I I & 	2 	2,1)	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2DaHHHHHHHHHIsR   	A
A

AA2B 
CCB(C(B,	,C/B,	0CCTallow_networkforce_refreshr   c                h   |sOt           rt           S t                      }|r*|a t                      }|t          j                    |z
  ndat           S | s2t           r+t          j                    t          z
  t
          k     rt           S | sDt           r=t                       t                       t          	                    d           t           S | st                      }|t                      }|r|a |t
          k     r@t          j                    |z
  at          	                    dt          |          |           n7t                       t                       t          	                    d|           t           S | s#t          j                    t          k     rt           S t          5  t          j                    }| s8t           rt           cddd           S |t          k     rt           cddd           S 	 t                      }t          |d           |cddd           S # t          $ r}t!          |d           Y d}~nd}~ww xY wt           sDt                      a dat           r-t          	                    dt          t                                t           cddd           S # 1 swxY w Y   dS )	u  Fetch models.dev registry. Cache hierarchy: in-mem → disk → network.

    Returns the full registry dict keyed by provider ID, or empty dict on failure.

    Cache hierarchy (when ``force_refresh=False``):
      1. Fresh in-memory cache → return immediately.
      2. Stale in-memory cache → return immediately and refresh in a single
         background daemon thread. Callers never block on the network while
         any cache exists; ``models.dev`` only changes when providers add
         new models, so stale data is preferable to a foreground timeout.
      3. Disk cache file (any age) → load, populate in-mem, return
         immediately. Stale disk caches trigger the same background refresh.
      4. No cache at all → singleflight foreground network fetch. On
         success, save to disk + in-mem and return.
      5. Any failed refresh (foreground or background) suppresses further
         automatic refreshes for 5 minutes process-wide.

    When ``force_refresh=True`` (used by ``hermes config refresh``, the
    "refresh model catalog" code path), cache fast paths and the failure
    backoff are bypassed; the function hits the network and only falls back
    to cached data if the call fails. When ``allow_network=False``, any
    memory or disk cache is returned regardless of age and no request is
    made — used by latency-sensitive paths (gateway route-identity checks)
    that must never wait on the network.
    Nr   z@Using stale in-memory models.dev cache; refreshing in backgroundzALoaded models.dev from fresh disk cache (%d providers, age=%.0fs)zGUsing stale models.dev disk cache (age=%.0fs); refreshing in background
foregroundr   z1Loaded stale models.dev disk cache (%d providers))r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r   r   	disk_datadisk_agenowr   r   s          r-   fetch_models_devr   i  s   <  
! 	%$$$&&	 	 ).00H*2*>	h&&A # ! 
 !! Y[[115JJJ    !. !!!!,...N	
 	
 	
 !   )*,,(**I )$-!333 .2Y[[8-C*LL458^^X   
 ,---8:::LL3   
 )(  !TY[[+BBB   
  ! !ikk 	)  )(	! ! ! ! ! ! ! !
 ,,,(! ! ! ! ! ! ! !	9133DT6666! ! ! ! ! ! ! !  	9 	9 	9!!<888888888	9 ! 	 0 2 2%&"  G)**  
 !7! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !s=   %#J'J'4 H!!
I+I<J'IAJ''J+.J+providermodelc                 "   t                               |           }|sdS t                      }|                    |          }t          |t                    sdS |                    di           }t          |t                    sdS |                    |          }|rt          |          }|r|S |                                }|                                D ]2\  }	}
|	                                |k    rt          |
          }|r|c S 3dD ]}||z   }|                    |          }|rt          |          }|r|c S ||z   }|                                D ]4\  }	}
|	                                |k    rt          |
          }|r|c c S 5dS )zLook up context_length for a provider+model combo in models.dev.

    Returns the context window in tokens, or None if not found.
    Handles case-insensitive matching and filters out context=0 entries.
    Nr   )z:cloudz-cloud)ru   r   r   r   r   _extract_contextloweritems)r   r   mdev_provider_idr   provider_datar   entryctxmodel_lowermidmdatasuffixsuffixed_keysuffixed_lowers                 r-   lookup_models_dev_contextr     s    .11(;; tDHH-..MmT** tx,,Ffd## t JJuE u%% 	J ++--Kllnn  
U99;;+%%"5))C 


 '  v~

<(( 	"5))C 


$v- ,,.. 	 	JCyy{{n,,&u-- JJJJJ		 4r/   r   c                    t          | t                    sdS |                     d          }t          |t                    sdS |                    d          }t          |t          t          f          r|dk    rt          |          S dS )zExtract context_length from a models.dev model entry.

    Returns None for invalid/zero values (some audio/image models have context=0).
    Nlimitcontextr   )r   r   r   rP   rQ   )r   r   r   s      r-   r   r   %  s    
 eT"" tIIgEeT"" t
))I

C#U|$$ q3xx4r/   c                   h    e Zd ZU dZdZeed<   dZeed<   dZeed<   dZ	e
ed<   d	Ze
ed
<   dZeed<   dS )ModelCapabilitiesz;Structured capability metadata for a model from models.dev.Tsupports_toolsFr2   supports_reasoning@ r       max_output_tokensr$   model_familyN)rI   rJ   rK   rL   r   rO   rN   r2   r   r   rP   r   r   rM   r   r/   r-   r   r   :  sz         EEND!OT!!!$$$$ NC   !s!!!L#r/   r   c                    t                               |           }|sdS t                      }|                    |          }t          |t                    sdS |                    di           }t          |t                    sdS |S )zResolve a Hermes provider ID to its models dict from models.dev.

    Returns the models dict or None if the provider is unknown or has no data.
    Nr   )ru   r   r   r   r   )r   r   r   r   r   s        r-   _get_provider_modelsr   F  s    
 .11(;; tDHH-..MmT** tx,,Ffd## tMr/   r   c                    |                      |          }t          |t                    r|S |                                }|                                 D ]6\  }}|                                |k    rt          |t                    r|c S 7dS )zBFind a model entry by exact match, then case-insensitive fallback.N)r   r   r   r   r   )r   r   r   r   r   r   s         r-   _find_model_entryr   [  s     JJuE%  ++--Kllnn  
U99;;+%%*UD*A*A%LLL4r/   c                    t          |           }|dS t          ||          }|dS t          |                    dd                    }|                    di           }t	          |t
                    r|                    d          }nd}t	          |t                    rd|v }n#t          |                    dd                    }t          |                    dd                    }|                    d	i           }t	          |t
                    si }|                    d
          }	t	          |	t          t          f          r|	dk    rt          |	          nd}
|                    d          }t	          |t          t          f          r|dk    rt          |          nd}|                    dd          pd}t          ||||
||          S )u  Look up full capability metadata from models.dev cache.

    Uses the existing fetch_models_dev() and PROVIDER_TO_MODELS_DEV mapping.
    Returns None if model not found.

    Extracts from model entry fields:
      - reasoning  (bool)  → supports_reasoning
      - tool_call  (bool)  → supports_tools
      - attachment (bool)  → supports_vision
      - limit.context (int) → context_window
      - limit.output  (int) → max_output_tokens
      - family     (str)   → model_family
    Nr   F
modalitiesinputr1   r   r   r   r   r   r   outputr   r   r$   )r   r2   r   r   r   r   )
r   r   rO   r   r   r   listrP   rQ   r   )r   r   r   r   r   
input_modsr2   r   r   r   r   outr   r   s                 r-   get_model_capabilitiesr   k  s    "(++F~tfe,,E}t %))K7788N <,,J*d## ^^G,,


*d## ?!Z/uyyu==>>eiiU;;<< IIgr""EeT"" 
))I

C!+C#u!>!>V377SXXXPVN
))H

C$.sS%L$A$AWcAggCSW99Xr**0bL%'-%+!   r/   c                      ddl m}  |           p  t                     }|g S  fd|                                D             S )zReturn all model IDs for a provider from models.dev.

    Returns an empty list if the provider is unknown or has no data.
    r   )normalize_providerNc                 4    g | ]}t          |          |S r   )"_should_hide_from_provider_catalog)r   r   r   s     r-   
<listcomp>z(list_provider_models.<locals>.<listcomp>  s9       1(C@@  r/   )hermes_cli.modelsr   r   keys)r   r   r   s   `  r-   list_provider_modelsr     sv    
 544444!!(++7xH!(++F~	   {{}}   r/   zZ-tts\b|embedding|live-|-(preview|exp)-\d{2,4}[-_]|-image\b|-image-preview\b|-customtools\b_NOISE_PATTERNS>   
gemma-3-1b
gemma-3-2b
gemma-3-4bgemma-3-12bgemma-3-27bgemma-3-1b-itgemma-3-2b-itgemma-3-4b-itgemini-1.5-progemma-3-12b-itgemma-3-27b-itgemma-4-26b-itgemma-4-31b-itgemini-1.5-flashgemini-2.0-flashgemma-4-26b-a4b-itgemini-1.5-flash-8bgemini-2.0-flash-litemodel_idc                     | pd                                                                 }|pd                                                                 }|dv r|t          v rdS dS )Nr$   >   rj   rk   TF)stripr   _GOOGLE_HIDDEN_MODELS)r   r  provider_lowerr   s       r-   r   r     se    n"++--3355N>r((**0022K---+AV2V2Vt5r/   c                 @   t          |           }|g S g }|                                D ]s\  }}t          |t                    st	          | |          r,|                    dd          sCt                              |          r^|                    |           t|S )zReturn model IDs suitable for agentic use from models.dev.

    Filters for tool_call=True and excludes noise (TTS, embedding,
    dated preview snapshots, live/streaming, image-only models).
    Returns an empty list on any failure.
    Nr   F)	r   r   r   r   r   r   r   searchr>   )r   r   resultr   r   s        r-   list_agentic_modelsr    s     "(++F~	Fllnn 	 	
U%&& 	-h<< 	yye,, 	!!#&& 	cMr/   rawr   c                    |                     d          pi }t          |t                    si }|                     d          pi }t          |t                    si }|                     d          pi }t          |t                    si }|                     d          pg }|                     d          pg }|                     d          }t          |t          t          f          r|dk    rt          |          nd}	|                     d          }
t          |
t          t          f          r|
dk    rt          |
          nd}|                     d          }t          |t          t          f          r|dk    rt          |          nd}t          di d	| d
|                     d
d          p| d|                     dd          pdd|dt          |                     dd                    dt          |                     dd                    dt          |                     dd                    dt          |                     dd                    dt          |                     dd                    dt          |                     dd                    dt          |t                    rt          |          nddt          |t                    rt          |          ndd|	d|d|dt	          |                     dd          pd          dt	          |                     dd          pd          dd|v r|d         t	          |d                   nddd |v r|d          t	          |d                    ndd!|                     d"d          pdd#|                     d#d          pdd$|                     d$d          pdd%|                     d%d          S )&zEConvert a raw models.dev model entry dict into a ModelInfo dataclass.r   costr   r   r   r   r   Nr   r   r$   r   r   r   Fr   r   r   r   r   r   r   r   r   r   r   r    r!   r"   
cache_readr#   cache_writer%   	knowledger&   r'   r(   )	r   r   r   rP   rQ   r   rO   r   tuple)r  r  r   r   r  r   r   output_modsr   ctx_intr   out_intinpinp_ints                 r-   _parse_model_infor'    s@   GGG"EeT"" 776?? bDdD!! &&,"Jj$'' 
((.BJ..**0bK
))I

C$S3,77JC!GGc#hhhG
))H

C$S3,77JC!GGc#hhhG
))G

C$S3,77MC!GGc#hhhG   8WWVR  ,H wwx$$*  K	
 sww{E22333 sww{E22333 e44555 66777 sww':EBBCCC #''.%88999 /9T.J.JRz***PR 1;;0M0MU%,,,SU w 7 '  '1--2333!" $((8Q//41555#$ 6BT5I5IdS_N`Nld<0111rv%& 8E7L7LQUVcQdQptM2333vz'( b117R)* WW^R006B+, wwx$$*-. GGM5111/ r/   c                    |                     d          pg }|                     d          pi }t          | |                     dd          p| t          |t                    rt	          |          nd|                     dd          pd|                     dd          pdt          |t
                    rt          |          nd	          S )
zAConvert a raw models.dev provider entry dict into a ProviderInfo.rT   r   r   r$   r   rU   rV   r   )r   r   rT   rU   rV   rW   )r   rS   r   r   r!  r   r   )r   r  rT   r   s       r-   _parse_provider_infor)  9  s    
''%..
BCWWX$"FWWVR  /K$S$//7E#JJJRGGE2$"GGE2$"#-fd#;#;BCKKK   r/   c                    t                               | |           }|rt                      nt          d          }|                    |          }t          |t                    sdS t          ||          S )zGet full provider metadata from models.dev.

    Accepts either a Hermes provider ID (e.g. "kilocode") or a models.dev
    ID (e.g. "kilo").  Returns None if the provider is not in the catalog.
    Fr   N)ru   r   r   r   r   r)  )r   r   mdev_idr   r  s        r-   get_provider_infor,  K  s|     %((kBBG 	3E222 	
 ((7

Cc4   t---r/   c                 \   t                               | |           }t                      }|                    |          }t          |t                    sdS |                    di           }t          |t                    sdS |                    |          }t          |t                    rt          |||          S |                                }|                                D ]E\  }}	|                                |k    r(t          |	t                    rt          ||	|          c S FdS )zGet full model metadata from models.dev.

    Accepts Hermes or models.dev provider ID.  Tries exact match then
    case-insensitive fallback.  Returns None if not found.
    Nr   )ru   r   r   r   r   r'  r   r   )
r   r  r+  r   pdatar   r  r   r   r   s
             r-   get_model_infor/  i  s    %((kBBGDHHWEeT"" tYYx$$Ffd## t **X

C#t 9 3888 ..""Kllnn : :
U99;;+%%*UD*A*A%$S%999994r/   )r)   N)F)HrL   r   loggingr   r   dataclassesr   pathlibr   typingr   r   r   r   r	   utilsr
   r   	getLoggerrI   r   r   r   r   r   rM   rN   r   rQ   r   Lockr   r   r   r   rS   ru   rv   r{   r   r   r   r   r   r   r   r   r   r   rO   r   rP   r   r   r   r   r   r   r   recompile
IGNORECASEr   Pattern	frozensetr  r   r  r'  r)  r,  r/  r   r/   r-   <module>r<     s+    0        ! ! ! ! ! !       3 3 3 3 3 3 3 3 3 3 3 3 3 3 # # # # # # 		8	$	$.   %' 4S> & & & !  ! ! !!"  " " "')) )9>++  %  K4 K4 K4 K4 K4 K4 K4 K4\         '*,'*k'* '* h	'*
 H'* 
5'* '* $'* !'* y'* ''* y'* Y'* ,'* 
'*  y!'*" )#'* '*$ %'*& (''*( J)'** =+'*, -'*. /'*0 =1'*2 h3'*4 h5'*6 
57'*< ='*> h?'*@ hA'*B FC'*D yE'*F ,G'*H ,I'* '*J "M'* '* '* S#X ' ' 'T 59 $sCx.1 8 8 87 7 7 7 7	$sCx. 	 	 	 	%    4D4S> Dd D D D DS#X    $
, 
, 
, 
,4S> S T    *y C D    2 2 2 2I I I I:  ~!:>~! ~! ~!~!37~!	#s(^~! ~! ~! ~!B8 8C 8HSM 8 8 8 8vDcN x}    *        3 8DcN+C    *d38n S Xd3PS8n=U     :S : :BS9T : : : :z3 49    & 
			(bj0M     "	 # # #   4      # $s)    <0 0$sCx. 0s 0y 0 0 0 0fc S#X <    & 04. . ..(,.l. . . .< #i     r/   