
    `gj'd              	       T   U d 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i ae
ee	f   ed	<   daeed
<   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+d,d-d-d-d.d.d/d.d0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7iZe
eef   ed8<   dZee
eef      ed9<   d:efd;Zd:e
ee	f   fd<Z d:ee   fd=Z!d>e
ee	f   d:dfd?Z"dZd@e#d:e
ee	f   fdAZ$dBedCed:ee%   fdDZ&dEe
ee	f   d:ee%   fdFZ'e G dG dH             Z(dBed:ee
ee	f      fdIZ)dJe
ee	f   dCed:ee
ee	f      fdKZ*dBedCed:ee(   fdLZ+dBed:ee   fdMZ,ddl-Z- e-j\                  dNe-j^                        Z0e-jb                  edO<    e2h dP      Z3dBedQed:e#fdRZ4dBed:ee   fdSZ5dQedTe
ee	f   dUed:efdVZ6dUedTe
ee	f   d:efdWZ7dUed:ee   fdXZ8dUedQed:ee   fdYZ9y)[u]  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 (like TypeScript OpenCode):
  1. Bundled snapshot (ships with the package — offline-first)
  2. Disk cache (~/.hermes/models_dev_cache.json)
  3. Network fetch (https://models.dev/api.json)
  4. Background refresh every 60 minutes

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  _models_dev_cache_models_dev_cache_timec                      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$y)'	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                 B    | j                   dkD  xs | j                  dkD  S )Nr   )r   r    selfs    C/root/.hermes/venv/lib/python3.12/site-packages/agent/models_dev.pyhas_cost_datazModelInfo.has_cost_dataT   s!    ":d&6&6&::    c                 :    | j                   xs d| j                  v S )Nimage)r   r   r*   s    r,   supports_visionzModelInfo.supports_visionW   s    B'T-B-B"BBr.   c                     d| j                   v S )Npdfr   r*   s    r,   supports_pdfzModelInfo.supports_pdfZ   s    ----r.   c                     d| j                   v S )Naudior4   r*   s    r,   supports_audio_inputzModelInfo.supports_audio_input]   s    $////r.   c                     | j                         syd| j                  ddd| j                  ddg}| j                   |j	                  d| j                  dd       dj                  |      S )	z<Human-readable cost string, e.g. '$3.00/M in, $15.00/M out'.unknown$z.2fz/M inz/M outzcache read $z/M, )r-   r   r    r!   appendjoin)r+   partss     r,   format_costzModelInfo.format_cost`   sv    !!#T__S)/1T5E5Ec4J&1QR+LL<(<(<S'ADEyyr.   c                    g }| j                   r|j                  d       | j                  r|j                  d       | j                         r|j                  d       | j	                         r|j                  d       | j                         r|j                  d       | j                  r|j                  d       | j                  r|j                  d       |rdj                  |      S d	S )
zBHuman-readable capabilities, e.g. 'reasoning, tools, vision, PDF'.r   toolsvisionPDFr7   zstructured outputzopen weightsr<   basic)	r   r=   r   r1   r5   r8   r   r   r>   )r+   capss     r,   format_capabilitieszModelInfo.format_capabilitiesi   s    >>KK$>>KK !KK!KK$$&KK !!KK+,KK'"&tyy3G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-   r1   r5   r8   r@   rG   r   r.   r,   r   r   .   sM   ;G
IK ItItJK#t#L$ )+eCHo*)+uS#X+ NCJ#Ix}# JK'+OXe_+(,huo, cL#FCK;t ;C C.d .0d 0 S  4S 4r.   r   c                   `    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
<   y)ProviderInfoz-Full metadata for a provider from models.dev.r   r   .envapir#   docr   model_countN)
rH   rI   rJ   rK   rL   rM   r	   rU   rV   rO   r   r.   r,   rR   rR   }   s5    7G
I	sCx	HCMKr.   rR   
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opencode-zenopencodezopencode-gokilocodekilo	fireworkszfireworks-aihuggingfacegeminigooglexaiz	xai-oauthxiaominvidiagroqmistral
togetherai
perplexitycoherezollama-cloud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_constantsrv   ru   s    r,   _get_cache_pathrx      s    0666r.   c                  
   	 t               } | j                         r,t        | d      5 }t        j                  |      cddd       S 	 i S # 1 sw Y   i S xY w# t
        $ r!}t        j                  d|       Y d}~i S d}~ww xY w)z%Load models.dev data from disk cache.zutf-8)encodingNz(Failed to load models.dev disk cache: %s)rx   existsopenjsonload	Exceptionloggerdebug)
cache_pathfes      r,   _load_disk_cacher      s    D$&
j73 $qyy|$ $ 
 I	$ I  D?CCIDs3   'A A	A AA A 	B!A==Bc                     	 t               } | j                         sy| j                         j                  }t	        j                         |z
  }|dk  ry|S # t
        $ r }t        j                  d|       Y d}~y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)rx   r{   statst_mtimetimer   r   r   )r   mtimeager   s       r,   _disk_cache_age_secondsr      ss    $&
  "!**iikE!
 7
 ?Cs"   A 6A A 	A?A::A?datac                     	 t               }t        || dd       y# t        $ r }t        j	                  d|       Y d}~y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)rx   r
   r   r   r   )r   r   r   s      r,   _save_disk_cacher      sB    D$&
*d4JO D?CCDs    	AA  Aforce_refreshc           	         | s.t         r(t        j                         t        z
  t        k  rt         S | s`t	               }|T|t        k  rKt               }|r?|a t        j                         |z
  at        j                  dt        |      |       t         S 	 t        j                  t        d      }|j                          |j                         }t        |t              rc|ra|a t        j                         at!        |       t        j                  dt        |      t#        d |j%                         D                     |S t         sQt               a t         rAt        j                         t        z
  dz   at        j                  d	t        t                      t         S # t&        $ r }t        j                  d|       Y d}~d}~ww xY w)
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. In-memory cache, populated and < TTL old → return immediately.
      2. **Disk cache file < TTL old by mtime → load, populate in-mem, return.**
         No network call. Saves ~500 ms per cold-start agent construction;
         ``models.dev`` only changes when providers add new models, so a
         1 hour staleness window is acceptable (same TTL as in-mem cache).
      3. Network fetch → on success, save to disk + in-mem and return.
      4. Network fails → fall back to ANY available disk cache (even stale)
         with a short 5 min in-mem grace period before retrying network.

    When ``force_refresh=True`` (used by ``hermes config refresh``, the
    "refresh model catalog" code path), stages 1 and 2 are skipped. The
    function always hits the network and only falls back to disk if the
    network call fails.
    NzALoaded models.dev from fresh disk cache (%d providers, age=%.0fs)   )timeoutz:Fetched models.dev registry: %d providers, %d total modelsc              3   t   K   | ]0  }t        |t              st        |j                  d i              2 yw)modelsN)
isinstancedictlenget).0ps     r,   	<genexpr>z#fetch_models_dev.<locals>.<genexpr>/  s+     [zRSUYGZCh+,[s   8 8zFailed to fetch models.dev: %si,  z0Loaded models.dev from disk cache (%d providers))r   r   r   _MODELS_DEV_CACHE_TTLr   r   r   r   r   requestsr   MODELS_DEV_URLraise_for_statusr}   r   r   r   sumvaluesr   )r   disk_age	disk_dataresponser   r   s         r,   fetch_models_devr      sp   2 YY[115JJ   *,H/D$D(*I$-! *.x)?&014Y )(:<<;!!#}}dD!d $%)YY["T"LLLD	[dkkm[[
 K ,.%)YY[3H%H3%N"LLKSQbMcd  :5q99:s   B-F 	G(GGprovidermodelc                    t         j                  |       }|syt               }|j                  |      }t        |t              sy|j                  di       }t        |t              sy|j                  |      }|rt        |      }|r|S |j                         }|j                         D ]*  \  }	}
|	j                         |k(  st        |
      }|s(|c S  dD ]o  }||z   }|j                  |      }|rt        |      }|r|c S ||z   }|j                         D ],  \  }	}
|	j                         |k(  st        |
      }|s(|c c S  q y)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)rr   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   A  sN    .11(;DHH-.MmT*x,Ffd# JJuEu%J ++-Klln 
U99;+%"5)C
	 ' v~

<("5)C
$v- ,,. 	JCyy{n,&u-J		 r.   r   c                     t        | t              sy| j                  d      }t        |t              sy|j                  d      }t        |t        t        f      r|dkD  rt        |      S y)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   rO   rP   )r   r   r   s      r,   r   r   |  sZ    
 eT"IIgEeT"
))I
C#U|$q3xr.   c                   f    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<   y)ModelCapabilitiesz;Structured capability metadata for a model from models.dev.Tsupports_toolsFr1   supports_reasoning@ r       max_output_tokensr#   model_familyN)rH   rI   rJ   rK   r   rN   rM   r1   r   r   rO   r   r   rL   r   r.   r,   r   r     sC    END!OT!$$ NC !s!L#r.   r   c                     t         j                  |       }|syt               }|j                  |      }t        |t              sy|j                  di       }t        |t              sy|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   )rr   r   r   r   r   )r   r   r   r   r   s        r,   _get_provider_modelsr     sc    
 .11(;DHH-.MmT*x,Ffd#Mr.   r   c                     | j                  |      }t        |t              r|S |j                         }| j	                         D ]-  \  }}|j                         |k(  st        |t              s+|c S  y)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     sh     JJuE% ++-Klln 
U99;+%*UD*AL r.   c                    t        |       }|yt        ||      }|yt        |j                  dd            }|j                  di       }t	        |t
              r|j                  d      }nd}t	        |t              rd|v }nt        |j                  dd            }t        |j                  dd            }|j                  d	i       }t	        |t
              si }|j                  d
      }	t	        |	t        t        f      r|	dkD  rt        |	      nd}
|j                  d      }t	        |t        t        f      r|dkD  rt        |      nd}|j                  dd      xs 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inputr0   r   r   r   r   r   r   outputr   r   r#   )r   r1   r   r   r   r   )
r   r   rN   r   r   r   listrO   rP   r   )r   r   r   r   r   
input_modsr1   r   r   r   r   outr   r   s                 r,   get_model_capabilitiesr     s_    "(+F~fe,E} %))K78N <,J*d#^^G,

*d#!Z/uyyu=>eiiU;< IIgr"EeT"
))I
C!+C#u!>37SXPVN
))H
C$.sS%L$AcAgCSW99Xr*0bL%'-%+! r.   c                     ddl m}  ||       xs | } t        |       }|g S |j                         D cg c]  }t	        | |      s| c}S c c}w )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_provider)hermes_cli.modelsr   r   keys"_should_hide_from_provider_catalog)r   r   r   r   s       r,   list_provider_modelsr     sZ    
 5!(+7xH!(+F~	{{}1(C@ 	  s   A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                     | xs dj                         j                         }|xs dj                         j                         }|dv r	|t        v ryy)Nr#   >   rh   ri   TF)stripr   _GOOGLE_HIDDEN_MODELS)r   r   provider_lowerr   s       r,   r   r   7  sO    n"++-335N>r((*002K--+AV2Vr.   c                    t        |       }|g S g }|j                         D ]]  \  }}t        |t              st	        | |      r$|j                  dd      s7t        j                  |      rM|j                  |       _ |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.
    r   F)	r   r   r   r   r   r   r   searchr=   )r   r   resultr   r   s        r,   list_agentic_modelsr   ?  s     "(+F~	Flln 	
U%&-h<yye,!!#&c	 Mr.   rawr   c                    |j                  d      xs i }t        |t              si }|j                  d      xs i }t        |t              si }|j                  d      xs i }t        |t              si }|j                  d      xs g }|j                  d      xs g }|j                  d      }t        |t        t        f      r|dkD  rt        |      nd}	|j                  d      }
t        |
t        t        f      r|
dkD  rt        |
      nd}|j                  d      }t        |t        t        f      r|dkD  rt        |      nd}t        di d	| d
|j                  d
d      xs | d|j                  dd      xs dd|dt        |j                  dd            dt        |j                  dd            dt        |j                  dd            dt        |j                  dd            dt        |j                  dd            dt        |j                  dd            dt        |t              rt        |      nddt        |t              rt        |      ndd|	d|d|dt	        |j                  dd      xs d      dt	        |j                  dd      xs d      dd|v r|d   t	        |d         nddd |v r|d    t	        |d          ndd!|j                  d"d      xs dd#|j                  d#d      xs dd$|j                  d$d      xs dd%|j                  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   rO   rP   r   rN   r   tuple)r   r   r   r   r   r   r   output_modsr   ctx_intr   out_intinpinp_ints                 r,   _parse_model_infor  ]  sR   GGG"EeT"776? bDdD!&,"Jj$'
(.BJ..*0bK
))I
C$S3,7C!Gc#hG
))H
C$S3,7C!Gc#hG
))G
C$S3,7C!Gc#hG WWVR ,H wwx$*  	
 sww{E23 sww{E23 e45 67 sww':EBC #''.%89 /9T.Jz*PR 1;;0M%,SU     '1-23!" $((8Q/415#$ 6BT5IdS_N`Nld<01rv%& 8E7LQUVcQdQptM23vz'( b17R)* WW^R06B+, wwx$*-. GGM51/ r.   c                 f   |j                  d      xs g }|j                  d      xs i }t        | |j                  dd      xs | t        |t              rt	        |      nd|j                  dd      xs d|j                  dd      xs dt        |t
              rt        |      	      S d	      S )
zAConvert a raw models.dev provider entry dict into a ProviderInfo.rS   r   r   r#   r   rT   rU   r   )r   r   rS   rT   rU   rV   )r   rR   r   r   r   r   r   )r   r   rS   r   s       r,   _parse_provider_infor    s    
''%.
BCWWX$"FWWVR /K$S$/E#JRGGE2$"GGE2$"#-fd#;CK  BC r.   c                     t         j                  | |       }t               }|j                  |      }t        |t              sy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.
    N)rr   r   r   r   r   r  )r   mdev_idr   r   s       r,   get_provider_infor    sF     %((kBGD
((7
Cc4 --r.   c                    t         j                  | |       }t               }|j                  |      }t        |t              sy|j                  di       }t        |t              sy|j                  |      }t        |t              rt        |||      S |j                         }|j                         D ]8  \  }}	|j                         |k(  st        |	t              s+t        ||	|      c S  y)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   )rr   r   r   r   r   r  r   r   )
r   r   r  r   pdatar   r   r   r   r   s
             r,   get_model_infor	    s     %((kBGDHHWEeT"YYx$Ffd# **X
C#t 388 .."Klln :
U99;+%*UD*A$S%99: r.   )F):rK   r}   loggingr   dataclassesr   pathlibr   typingr   r   r   r   r	   utilsr
   r   	getLoggerrH   r   r   r   r   rL   rM   r   rP   r   rR   rr   rs   rx   r   r   r   rN   r   rO   r   r   r   r   r   r   r   recompile
IGNORECASEr   Pattern	frozensetr   r   r   r  r  r  r	  r   r.   r,   <module>r     s  (    !  3 3 # 			8	$.  %' 4S> & !  ! K4 K4 K4\    &*,&*k&* &* h	&*
 H&* 
5&* &* $&* !&* y&* '&* y&* Y&* ,&* 
&*  y!&*" )#&*$ %&*& J'&*( =)&** +&*, -&*. =/&*0 h1&*2 h3&*4 
55&*: ;&*< h=&*> h?&*@ FA&*B yC&*D ,E&*F ,G&*H hI&*J NK&* S#X &R 59 $sCx.1 87 7	$sCx. 	% 4D4S> Dd DND NT#s(^ Nb8 8C 8HSM 8vDcN x} *   3 8DcN+C *d38n S Xd3PS8n=U  :S : :BS9T :z3 49 & 
(bjj0MM  " #  4   # $s) <0 0$sCx. 0s 0y 0fc S#X < $.3 .8L+A .* #ir.   