§
    ‰eîi÷ç  ã                   ój	  — U d Z ddlZddlZddlZddlZddlZddlmZ ddlm	Z	m
Z
mZmZ ddlmZ ddlZddlZddlmZmZ ddlmZ  ej        e¦  «        Zdeez  fd	„Z eh d
£¦  «        Zee         ed<    ej        dej         ¦  «        Z! ej"        d¦  «        Z#dedefd„Z$i a%e
ee
ee	f         f         ed<   da&e'ed<   dZ(i Z)e
ee
ee
ee	f         f         f         ed<   i Z*e
ee'f         ed<   dZ+g d¢Z,e,d         Z-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/d0“i d1d0“d2d0“d3d4“d5d6“d7d“d8d“d9d“d:d“d;d(“d<d4“d=d“d>d?“d@d4“dAdB“dCdD“dEd0“dFdG“¥i dHd6“dIdG“dJdG“dKd0“dLd4“dMd4“dNd4“dOd?“dPd4“dQd?“dRd?“dSd4“dTd4“dUdV“dWd?“dXd?“dYd?“¥dBd?d.d.d.d?d?dDdZœ¥Z/d[Z0d\Z1d]Z2d^Z3d_edefd`„Z4dÍdbede
eef         fdc„Z5d_edefdd„Z6d_edefde„Z7i dfdg“dhdg“didj“dkdl“dmdl“dndo“dpdq“drdo“dsdt“dudt“dvdw“dxdA“dydz“d{dz“d|d}“d~d“d€d-“d�d;d‚d‚dƒd„d…d†d‡d‡dˆd‰œ¥Z8e
eef         edŠ<   d_edee         fd‹„Z9d_edefdŒ„Z:d_edefd�„Z;dÍd_edbedee         fdŽ„Z<d�e	fd�„Z=dÎd�e	d“e>d”e>dee>         fd•„Z?d–e
ee	f         d—e@ed˜f         dee>         fd™„ZAd–e
ee	f         dee>         fdš„ZBd–e
ee	f         dee>         fd›„ZCd–e
ee	f         de
ee	f         fdœ„ZDd�e
ee
ee	f         f         džedŸe
ee	f         ddfd „ZEdÏd¢ede
ee
ee	f         f         fd£„ZF	 	 dÐd_edbed¢ede
ee
ee	f         f         fd¤„ZGdefd¥„ZHde
ee>f         fd¦„ZIded_ed§e>ddfd¨„ZJded_edee>         fd©„ZKded_eddfdª„ZLd«e>dee>         fd¬„ZMd­edee>         fd®„ZNd­edee>         fd¯„ZOd°ed±edefd²„ZPdÍded_edbedee>         fd³„ZQdÍded_edbedee>         fd´„ZRdedefdµ„ZSded_edbedee>         fd¶„ZTd·d·d·d·d·d·d·d·d·d¸œ	ZUe
ee>f         ed¹<   i aVe
ee>f         edº<   d»aWe'ed¼<   dZXd½ede
ee>f         fd¾„ZY	 dÍded½edee>         fd¿„ZZdedee>         fdÀ„Z[	 	 	 	 	 dÑded_edbedÁe>dz  dÂedÃe\dz  de>fdÄ„Z]dÅede>fdÆ„Z^dÇee
ee	f                  de>fdÈ„Z_daddÉœdÇee
ee	f                  dÊedËeee
ee	f                           de>fdÌ„Z`dS )Òz¿Model metadata, context lengths, and token estimation utilities.

Pure utility functions with no AIAgent dependency. Used by ContextCompressor
and run_agent.py for pre-flight context checks.
é    N)ÚPath)ÚAnyÚDictÚListÚOptional)Úurlparse)Úbase_url_host_matchesÚbase_url_hostname)ÚOPENROUTER_MODELS_URLÚreturnc                  ó‚   — dD ];} t          j        | ¦  «        }|r#t           j                             |¦  «        r|c S Œ<dS )aø  Resolve SSL verify setting for `requests` calls from env vars.

    The `requests` library only honours REQUESTS_CA_BUNDLE / CURL_CA_BUNDLE
    by default. Hermes also honours HERMES_CA_BUNDLE (its own convention)
    and SSL_CERT_FILE (used by the stdlib `ssl` module and by httpx), so
    that a single env var can cover both `requests` and `httpx` callsites
    inside the same process.

    Returns either a filesystem path to a CA bundle, or True to defer to
    the requests default (certifi).
    )ÚHERMES_CA_BUNDLEÚREQUESTS_CA_BUNDLEÚSSL_CERT_FILET)ÚosÚgetenvÚpathÚisfile)Úenv_varÚvals     ú6/home/div/.hermes/hermes-agent/agent/model_metadata.pyÚ_resolve_requests_verifyr      sO   € ð Oð ð ˆÝŒi˜Ñ Ô ˆØð 	•2”7—>’> #Ñ&Ô&ð 	ØˆJˆJˆJøØˆ4ó    >?   úx-aiúx.aiúz-aiúz.aiúkimi-cnúarcee-aiú	deep-seekú
ai-gatewayú
minimax-cnú
nvidia-nimúmoonshot-cnúqwen-portalúxiaomi-mimoúopencode-zenúgithub-modelsúgoogle-geminiúgoogle-ai-studioÚgoÚglmÚnimÚxaiÚzaiÚzenÚgrokÚkiloÚkimiÚmimoÚnousÚqwenÚarceeÚlocalÚzhipuÚaliyunÚclaudeÚcustomÚgeminiÚgithubÚgoogleÚnvidiaÚollamaÚvercelÚxiaomiÚalibabaÚarceeaiÚcopilotÚminimaxÚstepfunÚdeepseekÚkilocodeÚmoonshotÚnemotronÚopencodeÚ	anthropicÚ	dashscopeÚ
openrouterú
qwen-oauthúcopilot-acpúkimi-codingúopencode-goúollama-cloudúopenai-codexúgithub-copilotúkimi-coding-cnÚ_PROVIDER_PREFIXESzE^(\d+\.?\d*b|latest|stable|q\d|fp?\d|instruct|chat|coder|vision|text)z100.64.0.0/10Úmodelc                 ó,  — d| vs|                       d¦  «        r| S |                      dd¦  «        \  }}|                     ¦   «                              ¦   «         }|t          v r0t
                               |                     ¦   «         ¦  «        r| S |S | S )ua  Strip a recognised provider prefix from a model string.

    ``"local:my-model"`` â†’ ``"my-model"``
    ``"qwen3.5:27b"``   â†’ ``"qwen3.5:27b"``  (unchanged â€” not a provider prefix)
    ``"qwen:0.5b"``     â†’ ``"qwen:0.5b"``    (unchanged â€” Ollama model:tag)
    ``"deepseek:latest"``â†’ ``"deepseek:latest"``(unchanged â€” Ollama model:tag)
    ú:Úhttpé   )Ú
startswithÚsplitÚstripÚlowerrY   Ú_OLLAMA_TAG_PATTERNÚmatch)rZ   ÚprefixÚsuffixÚprefix_lowers       r   Ú_strip_provider_prefixrh   R   s�   € ð �%ÐÐ˜5×+Ò+¨FÑ3Ô3ÐØˆØ—[’[  aÑ(Ô(�N€FˆFØ—<’<‘>”>×'Ò'Ñ)Ô)€LØÕ)Ð)Ð)å×$Ò$ V§\¢\¡^¤^Ñ4Ô4ð 	ØˆLØˆØ€Lr   Ú_model_metadata_cacheÚ_model_metadata_cache_timei  Ú_endpoint_model_metadata_cacheÚ#_endpoint_model_metadata_cache_timei,  )é è é ô é ú  i }  i€>  i@  ro   zclaude-opus-4-7i@B zclaude-opus-4.7zclaude-opus-4-6zclaude-sonnet-4-6zclaude-opus-4.6zclaude-sonnet-4.6r;   i@ úgpt-5.5i� zgpt-5.4-nanoé€ úgpt-5.4-miniúgpt-5.4zgpt-5.1-chatrn   úgpt-5zgpt-4.1iü zgpt-4r=   i   zgemma-4rm   Úgemma4zgemma-4-31bzgemma-3i   Úgemmai    zdeepseek-v4-prozdeepseek-v4-flashzdeepseek-chatzdeepseek-reasonerrI   Úllamazqwen3-coder-pluszqwen3-coderi   r6   rG   i   r,   i  zgrok-code-fastzgrok-4-1-fasti€„ zgrok-2-visionzgrok-4-fastz	grok-4.20zgrok-4zgrok-3zgrok-2r1   r3   rL   ÚtrinityÚelephantzQwen/Qwen3.5-397B-A17BzQwen/Qwen3.5-35B-A3Bzdeepseek-ai/DeepSeek-V3.2i   zmoonshotai/Kimi-K2.5zmoonshotai/Kimi-K2.6zmoonshotai/Kimi-K2-Thinking)zMiniMaxAI/MiniMax-M2.5zXiaomiMiMo/MiMo-V2-Flashzmimo-v2-prozmimo-v2.5-proz	mimo-v2.5zmimo-v2-omnizmimo-v2-flashzzai-org/GLM-5)Úcontext_lengthÚcontext_windowÚmax_context_lengthÚmax_position_embeddingsÚmax_model_lenÚmax_input_tokensÚmax_sequence_lengthÚmax_seq_lenÚn_ctx_trainÚn_ctxÚctx_size)Úmax_completion_tokensÚmax_output_tokensÚ
max_tokens)Ú	localhostz	127.0.0.1z::1z0.0.0.0)z.docker.internalz.containers.internalz.lima.internalÚbase_urlc                 óT   — | pd                      ¦   «                              d¦  «        S )NÚ ú/)ra   Úrstrip©r‰   s    r   Ú_normalize_base_urlr�     s&   € ØˆN˜×!Ò!Ñ#Ô#×*Ò*¨3Ñ/Ô/Ð/r   r‹   Úapi_keyc                 ó^   — t          | pd¦  «                             ¦   «         }|si S dd|› �iS )Nr‹   ÚAuthorizationúBearer )Ústrra   )r�   Útokens     r   Ú_auth_headersr–   
  s@   € Ý��˜2ÑÔ×$Ò$Ñ&Ô&€EØð Øˆ	ØÐ. uÐ.Ð.Ð/Ð/r   c                 ó"   — t          | d¦  «        S )Núopenrouter.ai)r	   rŽ   s    r   Ú_is_openrouter_base_urlr™     s   € Ý  ¨?Ñ;Ô;Ð;r   c                 ó^   — t          | ¦  «        }t          |¦  «        ot          |¦  «         S ©N)r�   Úboolr™   )r‰   Ú
normalizeds     r   Ú_is_custom_endpointrž     s.   € Ý$ XÑ.Ô.€JÝ�
ÑÔÐGÕ$;¸JÑ$GÔ$GÐ GÐGr   zapi.openai.comÚopenaizchatgpt.comúapi.anthropic.comrN   zapi.z.air/   zopen.bigmodel.cnzapi.moonshot.airS   zapi.moonshot.cnrX   zapi.kimi.comzapi.stepfun.airH   zapi.stepfun.comzapi.arcee.air7   zapi.minimaxzdashscope.aliyuncs.comrD   zdashscope-intl.aliyuncs.comzportal.qwen.airQ   r˜   rP   z!generativelanguage.googleapis.comr5   rF   Ú	fireworksrT   r.   r@   rC   rU   )zinference-api.nousresearch.comzapi.deepseek.comzapi.githubcopilot.comzmodels.github.aizapi.fireworks.aizopencode.aizapi.x.aizintegrate.api.nvidia.comzapi.xiaomimimo.comzxiaomimimo.comz
ollama.comÚ_URL_TO_PROVIDERc                 ó  — t          | ¦  «        }|sdS t          d|v r|nd|› �¦  «        }|j                             ¦   «         p|j                             ¦   «         }t
                               ¦   «         D ]\  }}||v r|c S ŒdS )a  Infer the models.dev provider name from a base URL.

    This allows context length resolution via models.dev for custom endpoints
    like DashScope (Alibaba), Z.AI, Kimi, etc. without requiring the user to
    explicitly set the provider name in config.
    Nú://zhttps://)r�   r   Únetlocrb   r   r¢   Úitems)r‰   r�   ÚparsedÚhostÚurl_partÚproviders         r   Ú_infer_provider_from_urlr«   :  s¦   € õ % XÑ.Ô.€JØð ØˆtÝ E¨ZÐ$7Ð$7�j�jÐ=TÈ
Ð=TÐ=TÑUÔU€FØŒ=×ÒÑ Ô Ð7 F¤K×$5Ò$5Ñ$7Ô$7€DÝ.×4Ò4Ñ6Ô6ð ð Ñˆ�(Ø�tÐÐØˆOˆOˆOð àˆ4r   c                 ó$   — t          | ¦  «        d uS r›   )r«   rŽ   s    r   Ú_is_known_provider_base_urlr­   L  s   € Ý# HÑ-Ô-°TÐ9Ð9r   c                 ó  ‡— t          | ¦  «        }|sdS d|v r|nd|› �}	 t          |¦  «        }|j        pdŠn# t          $ r Y dS w xY w‰t          v rdS t          ˆfd„t          D ¦   «         ¦  «        rdS 	 t          j        ‰¦  «        }|j	        s|j
        s|j        rdS t          |t          j        ¦  «        r|t          v rdS n# t          $ r Y nw xY w‰                     d¦  «        }t#          |¦  «        dk    r‚	 t%          |d	         ¦  «        t%          |d
         ¦  «        }}|dk    rdS |dk    rd|cxk    rdk    rn ndS |dk    r|dk    rdS |dk    rd|cxk    rdk    rn ndS n# t          $ r Y nw xY wdS )aÙ  Return True if base_url points to a local machine.

    Recognises loopback (``localhost``, ``127.0.0.0/8``, ``::1``),
    container-internal DNS names (``host.docker.internal`` et al.),
    RFC-1918 private ranges (``10/8``, ``172.16/12``, ``192.168/16``),
    link-local, and Tailscale CGNAT (``100.64.0.0/10``). Tailscale CGNAT
    is included so remote-but-trusted Ollama boxes reached over a
    Tailscale mesh get the same timeout auto-bumps as localhost Ollama.
    Fr¤   zhttp://r‹   Tc              3   óB   •K  — | ]}‰                      |¦  «        V — Œd S r›   )Úendswith)Ú.0rf   r¨   s     €r   ú	<genexpr>z$is_local_endpoint.<locals>.<genexpr>f  s/   øè è € Ð
IÐ
I Vˆ4�=Š=˜Ñ Ô Ð
IÐ
IÐ
IÐ
IÐ
IÐ
Ir   ú.é   r   r^   é
   é¬   é   é   éÀ   é¨   éd   é@   é   )r�   r   ÚhostnameÚ	ExceptionÚ_LOCAL_HOSTSÚanyÚ_CONTAINER_LOCAL_SUFFIXESÚ	ipaddressÚ
ip_addressÚ
is_privateÚis_loopbackÚis_link_localÚ
isinstanceÚIPv4AddressÚ_TAILSCALE_CGNATÚ
ValueErrorr`   ÚlenÚint)	r‰   r�   Úurlr§   ÚaddrÚpartsÚfirstÚsecondr¨   s	           @r   Úis_local_endpointrÓ   P  s  ø€ õ % XÑ.Ô.€JØð ØˆuØ Ð+Ð+ˆ*ˆ*Ð1G¸:Ð1GÐ1G€CðÝ˜#‘”ˆØŒÐ$ "ˆˆøÝð ð ð Øˆuˆuðøøøà�|ÐÐØˆtå
Ð
IÐ
IÐ
IÐ
IÕ/HÐ
IÑ
IÔ
IÑIÔIð ØˆtðÝÔ# DÑ)Ô)ˆØŒ?ð 	˜dÔ.ð 	°$Ô2Dð 	Ø�4Ý�d�IÔ1Ñ2Ô2ð 	°tÕ?OÐ7OÐ7OØ�4øøÝð ð ð Øˆðøøøð �JŠJ�s‰OŒO€EÝ
ˆ5�z„z�Q‚€ð	Ý  a¤™MœM­3¨u°Q¬x©=¬=�6ˆEØ˜Š{ˆ{Ø�tØ˜Š|ˆ|  fÐ 2Ð 2Ò 2Ð 2°Ò 2Ð 2Ð 2Ð 2Ð 2Ø�tØ˜Š|ˆ| ¨#¢ Ø�tØ˜Š|ˆ|  fÐ 3Ð 3Ò 3Ð 3°Ò 3Ð 3Ð 3Ð 3Ð 3Ø�tøøÝð 	ð 	ð 	ØˆDð	øøøàˆ5sK   ¡: º
AÁAÁ9)C
 Â$#C
 Ã

CÃCÄ0E4 Ä5E4 ÅE4 ÅE4 Å4
FÆ Fc                 ó  — ddl }t          | ¦  «        }|}|                     d¦  «        r
|dd…         }t          |¦  «        }	 |                     d|¬¦  «        5 }	 |                     |› d�¦  «        }|j        dk    r	 ddd¦  «         d	S n# t          $ r Y nw xY w	 |                     |› d
�¦  «        }|j        dk    r8	 |                     ¦   «         }d|v r	 ddd¦  «         dS n# t          $ r Y nw xY wn# t          $ r Y nw xY w	 |                     |› d�¦  «        }|j        dk    r|                     |› d�¦  «        }|j        dk    rd|j	        v r	 ddd¦  «         dS n# t          $ r Y nw xY w	 |                     |› d�¦  «        }|j        dk    r&|                     ¦   «         }d|v r	 ddd¦  «         dS n# t          $ r Y nw xY wddd¦  «         n# 1 swxY w Y   n# t          $ r Y nw xY wdS )zšDetect which local server is running at base_url by probing known endpoints.

    Returns one of: "ollama", "lm-studio", "vllm", "llamacpp", or None.
    r   Nú/v1éýÿÿÿg       @©ÚtimeoutÚheadersú/api/v1/modelséÈ   ú	lm-studioz	/api/tagsÚmodelsrA   ú	/v1/propsú/propsÚdefault_generation_settingsÚllamacppz/versionÚversionÚvllm)
Úhttpxr�   r°   r–   ÚClientÚgetÚstatus_coder¿   ÚjsonÚtext)	r‰   r�   rä   r�   Ú
server_urlrÙ   ÚclientÚrÚdatas	            r   Údetect_local_server_typerî   „  s`  € ð
 €L€L€Lå$ XÑ.Ô.€JØ€JØ×Ò˜5Ñ!Ô!ð %Ø   ”_ˆ
å˜GÑ$Ô$€Gð*Ø�\Š\ #¨wˆ\Ñ7Ô7ð '	¸6ðØ—J’J *Ð<Ð<Ð<Ñ=Ô=�Ø”= CÒ'Ð'Ø&ð'	ð '	ð '	ñ '	ô '	ð '	ð '	ð '	ð (øåð ð ð Ø�ðøøøð

Ø—J’J *Ð7Ð7Ð7Ñ8Ô8�Ø”= CÒ'Ð'ðØ Ÿvšv™xœx˜Ø# tÐ+Ð+Ø#+ð#'	ð '	ð '	ñ '	ô '	ð '	ð '	ð '	ð  ,øå$ð ð ð Ø˜ðøøøøøåð ð ð Ø�ðøøøðØ—J’J *Ð7Ð7Ð7Ñ8Ô8�Ø”= CÒ'Ð'ØŸ
š
 jÐ#8Ð#8Ð#8Ñ9Ô9�AØ”= CÒ'Ð'Ð,IÈQÌVÐ,SÐ,SØ%ð9'	ð '	ð '	ñ '	ô '	ð '	ð '	ð '	øøõ: ð ð ð Ø�ðøøøðØ—J’J *Ð6Ð6Ð6Ñ7Ô7�Ø”= CÒ'Ð'ØŸ6š6™8œ8�DØ  DÐ(Ð(Ø%ðK'	ð '	ð '	ñ '	ô '	ð '	ð '	ð '	øøõL ð ð ð Ø�ðøøøðM'	ð '	ð '	ñ '	ô '	ð '	ð '	ð '	ð '	ð '	ð '	øøøð '	ð '	ð '	ð '	øøõP ð ð ð Øˆðøøøð ˆ4s  ÁG/ ÁG#Á#BÂG/ ÂG#Â
BÂG#ÂBÂG#Â!#C=ÃC,ÃG/ Ã+C=Ã,
C9Ã6C=Ã8C9Ã9C=Ã<G#Ã=
D
ÄG#Ä	D
Ä
G#ÄAE,ÅG/ Å+G#Å,
E9Å6G#Å8E9Å9G#Å=;GÆ9G/ ÇG#Ç
GÇG#ÇGÇG#ÇG/ Ç#G'Ç'G/ Ç*G'Ç+G/ Ç/
G<Ç;G<Úvaluec              #   óú   K  — t          | t          ¦  «        r2| V — |                      ¦   «         D ]}t          |¦  «        E d {V —† Œd S t          | t          ¦  «        r| D ]}t          |¦  «        E d {V —† Œd S d S r›   )rÈ   ÚdictÚvaluesÚ_iter_nested_dictsÚlist)rï   ÚnestedÚitems      r   ró   ró   Á  s½   è è € Ý�%�ÑÔð 0ØˆˆˆØ—l’l‘n”nð 	2ð 	2ˆFÝ)¨&Ñ1Ô1Ð1Ð1Ð1Ð1Ð1Ð1Ð1Ð1ð	2ð 	2å	�E�4Ñ	 Ô	 ð 0Øð 	0ð 	0ˆDÝ)¨$Ñ/Ô/Ð/Ð/Ð/Ð/Ð/Ð/Ð/Ð/ð0ð 0ð	0ð 	0r   é   é€–˜ ÚminimumÚmaximumc                 ó$  — 	 t          | t          ¦  «        rd S t          | t          ¦  «        r(|                      ¦   «                              dd¦  «        } t          | ¦  «        }n# t          t          f$ r Y d S w xY w||cxk    r|k    rn n|S d S )NÚ,r‹   )rÈ   rœ   r”   ra   ÚreplacerÍ   Ú	TypeErrorrË   )rï   rù   rú   Úresults       r   Ú_coerce_reasonable_intr   Ë  s­   € ðÝ�e�TÑ"Ô"ð 	Ø�4Ý�e�SÑ!Ô!ð 	3Ø—K’K‘M”M×)Ò)¨#¨rÑ2Ô2ˆEÝ�U‘”ˆˆøÝ•zÐ"ð ð ð Øˆtˆtðøøøà�&Ð#Ð#Ò#Ð#˜GÒ#Ð#Ð#Ð#Ð#ØˆØˆ4s   ‚A& ™AA& Á&A;Á:A;ÚpayloadÚkeys.c                 óì   — d„ |D ¦   «         }t          | ¦  «        D ]W}|                     ¦   «         D ]@\  }}t          |¦  «                             ¦   «         |vrŒ)t	          |¦  «        }|�|c c S ŒAŒXd S )Nc                 ó6   — h | ]}|                      ¦   «         ’ŒS © )rb   )r±   Úkeys     r   ú	<setcomp>z%_extract_first_int.<locals>.<setcomp>Ú  s    € Ð*Ð*Ð*˜cˆc�iŠi‰kŒkÐ*Ð*Ð*r   )ró   r¦   r”   rb   r   )r  r  ÚkeysetÚmappingr  rï   Úcoerceds          r   Ú_extract_first_intr  Ù  s–   € Ø*Ð* TÐ*Ñ*Ô*€FÝ% gÑ.Ô.ð ð ˆØ!Ÿ-š-™/œ/ð 	ð 	‰JˆC�Ý�3‰xŒx�~Š~ÑÔ vÐ-Ð-ØÝ,¨UÑ3Ô3ˆGØÐ"Ø�����ð #ð		ð ˆ4r   c                 ó,   — t          | t          ¦  «        S r›   )r  Ú_CONTEXT_LENGTH_KEYS©r  s    r   Ú_extract_context_lengthr  å  ó   € Ý˜gÕ';Ñ<Ô<Ð<r   c                 ó,   — t          | t          ¦  «        S r›   )r  Ú_MAX_COMPLETION_KEYSr  s    r   Ú_extract_max_completion_tokensr  é  r  r   c                 óX  ‡— ddddddœ}t          | ¦  «        D ]�}d„ |                     ¦   «         D ¦   «         Št          ˆfd„|                     ¦   «         D ¦   «         ¦  «        sŒNi }|                     ¦   «         D ]%\  }}|D ]}|‰v r‰|         d	vr‰|         ||<    nŒŒ&|r|c S Œ‘i S )
N)ÚpromptÚinputÚinput_cost_per_tokenÚprompt_token_cost)Ú
completionÚoutputÚoutput_cost_per_tokenÚcompletion_token_cost)ÚrequestÚrequest_cost)Ú
cache_readÚcached_promptÚinput_cache_readÚcache_read_cost_per_token)Úcache_writeÚcache_creationÚinput_cache_writeÚcache_write_cost_per_token)r  r  r  r  r#  c                 óX   — i | ]'\  }}t          |¦  «                             ¦   «         |“Œ(S r  )r”   rb   )r±   r  rï   s      r   ú
<dictcomp>z$_extract_pricing.<locals>.<dictcomp>ö  s.   € ÐPÐPÐP±*°#°u•c˜#‘h”h—n’nÑ&Ô&¨ÐPÐPÐPr   c              3   óN   •K  — | ]}t          ˆfd „|D ¦   «         ¦  «        V — Œ dS )c              3   ó    •K  — | ]}|‰v V — Œ	d S r›   r  )r±   Úaliasr�   s     €r   r²   z-_extract_pricing.<locals>.<genexpr>.<genexpr>÷  s(   øè è € Ð@Ð@¨u�u 
Ð*Ð@Ð@Ð@Ð@Ð@Ð@r   N)rÁ   )r±   Úaliasesr�   s     €r   r²   z#_extract_pricing.<locals>.<genexpr>÷  s@   øè è € ÐcÐcÀW•3Ð@Ð@Ð@Ð@¸Ð@Ñ@Ô@Ñ@Ô@ÐcÐcÐcÐcÐcÐcr   )Nr‹   )ró   r¦   rÁ   rò   )r  Ú	alias_mapr	  ÚpricingÚtargetr,  r+  r�   s          @r   Ú_extract_pricingr0  í  s  ø€ àRØ`Ø.ØfØkðð €Iõ & gÑ.Ô.ð ð ˆØPÐPÀÇÂÁÄÐPÑPÔPˆ
ÝÐcÐcÐcÐcÐPY×P`ÒP`ÑPbÔPbÐcÑcÔcÑcÔcð 	ØØ"$ˆØ(ŸšÑ0Ô0ð 	ð 	‰OˆF�GØ ð ð �Ø˜JÐ&Ð&¨:°eÔ+<ÀJÐ+NÐ+NØ&0°Ô&7�G˜F‘OØ�EøøØð 	ØˆNˆNˆNð	à€Ir   ÚcacheÚmodel_idÚentryc                 ó€   — || |<   d|v r4|                      dd¦  «        d         }|                      ||¦  «         d S d S )NrŒ   r^   )r`   Ú
setdefault)r1  r2  r3  Ú
bare_models       r   Ú_add_model_aliasesr7    sO   € Ø€Eˆ(�OØ
ˆh€€Ø—^’^ C¨Ñ+Ô+¨AÔ.ˆ
Ø×Ò˜ UÑ+Ô+Ð+Ð+Ð+ð €r   FÚforce_refreshc                 ó°  — | s2t           r+t          j        ¦   «         t          z
  t          k     rt           S 	 t	          j        t          dt          ¦   «         ¬¦  «        }|                     ¦   «          | 	                    ¦   «         }i }|                     dg ¦  «        D ]Ã}|                     dd¦  «        }|                     dd¦  «        |                     di ¦  «                             d	d
¦  «        |                     d|¦  «        |                     di ¦  «        dœ}t          |||¦  «         |                     dd¦  «        }|r||k    rt          |||¦  «         ŒÄ|a t          j        ¦   «         at                               dt          |¦  «        ¦  «         |S # t          $ r*}t          j        d|› �¦  «         t           pi cY d}~S d}~ww xY w)z9Fetch model metadata from OpenRouter (cached for 1 hour).rµ   )rØ   Úverifyrí   Úidr‹   rz   rn   Útop_providerr…   i   Únamer.  )rz   r…   r=  r.  Úcanonical_slugz.Fetched metadata for %s models from OpenRouterz0Failed to fetch model metadata from OpenRouter: N)ri   Útimerj   Ú_MODEL_CACHE_TTLÚrequestsræ   r   r   Úraise_for_statusrè   r7  ÚloggerÚdebugrÌ   r¿   ÚloggingÚwarning)	r8  Úresponserí   r1  rZ   r2  r3  Ú	canonicalÚes	            r   Úfetch_model_metadatarJ    sÜ  € ð ð %Õ2ð %½¼	¹¼ÕF`Ñ8`ÕdtÒ7tÐ7tÝ$Ð$ð+Ý”<Õ 5¸rÕJbÑJdÔJdÐeÑeÔeˆØ×!Ò!Ñ#Ô#Ð#Ø�}Š}‰ŒˆàˆØ—X’X˜f bÑ)Ô)ð 	<ð 	<ˆEØ—y’y  rÑ*Ô*ˆHà"'§)¢)Ð,<¸fÑ"EÔ"EØ).¯ª°>À2Ñ)FÔ)F×)JÒ)JÐKbÐdhÑ)iÔ)iØŸ	š	 &¨(Ñ3Ô3Ø Ÿ9š9 Y°Ñ3Ô3ð	ð ˆEõ ˜u h°Ñ6Ô6Ð6ØŸ	š	Ð"2°BÑ7Ô7ˆIØð <˜Y¨(Ò2Ð2Ý" 5¨)°UÑ;Ô;Ð;øà %ÐÝ%)¤Y¡[¤[Ð"Ý�ŠÐEÅsÈ5ÁzÄzÑRÔRÐRØˆøåð +ð +ð +ÝŒÐNÈ1ÐNÐNÑOÔOÐOÝ$Ð*¨Ð*Ð*Ð*Ð*Ð*Ð*øøøøð+øøøs   ¶E*F! Æ!
GÆ+GÇ
GÇGc                 ó˜  — t          | ¦  «        }|rt          |¦  «        ri S |sXt                               |¦  «        }t                               |d¦  «        }|�!t          j        ¦   «         |z
  t          k     r|S |g}|                     d¦  «        r|dd…                              d¦  «        }n|dz   }|r||vr| 	                    |¦  «         |rdd|› �ini }d}	t          |¦  «        �r’	 t          ||¬¦  «        d	k    �ra|                     d¦  «        r|dd…                              d¦  «        n|}
t          j        |
                     d¦  «        d
z   |dt          ¦   «         ¬¦  «        }|                     ¦   «          |                     ¦   «         }i }|                     dg ¦  «        D �]Š}t!          |t"          ¦  «        sŒ|                     d¦  «        p|                     d¦  «        }|sŒFd|                     d|¦  «        i}d}|                     dg ¦  «        pg D ]y}t!          |t"          ¦  «        sŒ|                     di ¦  «        }t!          |t"          ¦  «        r|                     d¦  «        nd}t!          |t$          ¦  «        r
|dk    r|} nŒz|€t'          |¦  «        }|�||d<   t)          |¦  «        }|�||d<   t+          |¦  «        }|r||d<   t-          |||¦  «         |                     d¦  «        }t!          |t.          ¦  «        r|r||k    rt-          |||¦  «         �ŒŒ|t          |<   t          j        ¦   «         t          |<   |S n# t0          $ r}|}	Y d}~nd}~ww xY w|D �]�}|                     d¦  «        dz   }	 t          j        ||dt          ¦   «         ¬¦  «        }|                     ¦   «          |                     ¦   «         }i }|                     dg ¦  «        D ]›}t!          |t"          ¦  «        sŒ|                     d¦  «        }|sŒ0d|                     d|¦  «        i}t'          |¦  «        }|�||d<   t)          |¦  «        }|�||d<   t+          |¦  «        }|r||d<   t-          |||¦  «         Œœt3          d„ |                     dg ¦  «        D ¦   «         ¦  «        }|rõ	 |                     d¦  «                             dd¦  «        }t          ¦   «         }t          j        |dz   |d|¬¦  «        }|j        st          j        |dz   |d|¬¦  «        }|j        rh|                     ¦   «         }|                     di ¦  «        } |                      d¦  «        }!|                     dd¦  «        }"|!r|"r|"|v r|!||"         d<   n# t0          $ r Y nw xY w|t          |<   t          j        ¦   «         t          |<   |c S # t0          $ r}|}	Y d}~�Œ{d}~ww xY w|	rt8                               d ||	¦  «         i t          |<   t          j        ¦   «         t          |<   i S )!zãFetch model metadata from an OpenAI-compatible ``/models`` endpoint.

    This is used for explicit custom endpoints where hardcoded global model-name
    defaults are unreliable. Results are cached in memory per base URL.
    r   NrÕ   rÖ   rŒ   r’   r“   ©r�   rÜ   rÚ   rµ   ©rÙ   rØ   r:  rÝ   r  r;  r=  Úloaded_instancesÚconfigrz   r…   r.  z/modelsrí   c              3   ór   K  — | ]2}t          |t          ¦  «        ¯|                     d ¦  «        dk    V — Œ3dS )Úowned_byrá   N)rÈ   rñ   ræ   )r±   Úms     r   r²   z0fetch_endpoint_model_metadata.<locals>.<genexpr>ž  sV   è è € ð ð àµJ¸qÅ$Ñ4GÔ4GðØ—’�jÑ!Ô! ZÒ/ðð ð ð ð ð r   r‹   rÞ   é   rß   rà   rƒ   Úmodel_aliasz1Failed to fetch model metadata from %s/models: %s)r�   r™   rk   ræ   rl   r?  Ú_ENDPOINT_MODEL_CACHE_TTLr°   r�   ÚappendrÓ   rî   rA  r   rB  rè   rÈ   rñ   rÍ   r  r  r0  r7  r”   r¿   rÁ   rý   ÚokrC  rD  )#r‰   r�   r8  r�   ÚcachedÚ	cached_atÚ
candidatesÚ	alternaterÙ   Ú
last_errorrê   rG  r  r1  rZ   r2  r3  rz   ÚinstÚcfgÚctxr…   r.  Úalt_idÚexcÚ	candidaterÎ   Úis_llamacppÚbaseÚ_verifyÚ
props_respÚpropsÚgen_settingsrƒ   rT  s#                                      r   Úfetch_endpoint_model_metadatari  /  s6  € õ % XÑ.Ô.€JØð Õ0°Ñ<Ô<ð Øˆ	àð Ý/×3Ò3°JÑ?Ô?ˆÝ7×;Ò;¸JÈÑJÔJˆ	ØÐ¥4¤9¡;¤;°Ñ#:Õ>WÒ"WÐ"WØˆMà�€JØ×Ò˜5Ñ!Ô!ð 'Ø˜s ˜s”O×*Ò*¨3Ñ/Ô/ˆ	ˆ	à Ñ&ˆ	Øð %�Y jÐ0Ð0Ø×Ò˜)Ñ$Ô$Ð$à8?ÐGˆÐ 3¨'Ð 3Ð 3Ð4Ð4ÀR€GØ&*€Jå˜Ñ$Ô$ñ 4ð3	Ý'¨
¸GÐDÑDÔDÈÒSÑSØ<F×<OÒ<OÐPUÑ<VÔ<VÐf˜Z¨¨¨œ_×3Ò3°CÑ8Ô8Ð8Ð\f�
Ý#œ<Ø×%Ò% cÑ*Ô*Ð-=Ñ=Ø#ØÝ3Ñ5Ô5ð	ñ ô �ð ×)Ò)Ñ+Ô+Ð+Ø"Ÿ-š-™/œ/�Ø35�Ø$Ÿ[š[¨°2Ñ6Ô6ð !Añ !A�EÝ% e­TÑ2Ô2ð !Ø Ø$Ÿyšy¨Ñ/Ô/ÐB°5·9²9¸T±?´?�HØ#ð !Ø Ø-3°U·Y²Y¸vÀxÑ5PÔ5PÐ,Q�Eà%)�NØ %§	¢	Ð*<¸bÑ AÔ AÐ GÀRð "ð "˜Ý)¨$µÑ5Ô5ð %Ø$Ø"Ÿhšh x°Ñ4Ô4˜Ý;EÀcÍ4Ñ;PÔ;PÐZ˜cŸgšgÐ&6Ñ7Ô7Ð7ÐVZ˜Ý% c­3Ñ/Ô/ð "°C¸!²G°GØ-0˜NØ!˜EøØ%Ð-Ý)@ÀÑ)GÔ)G˜Ø%Ð1Ø2@˜Ð.Ñ/å,JÈ5Ñ,QÔ,QÐ)Ø,Ð8Ø9N˜Ð5Ñ6å.¨uÑ5Ô5�GØð 3Ø+2˜˜iÑ(å& u¨h¸Ñ>Ô>Ð>Ø"ŸYšY t™_œ_�FÝ! &­#Ñ.Ô.ð A°6ð A¸fÈÒ>PÐ>PÝ*¨5°&¸%Ñ@Ô@Ð@ùà=BÕ.¨zÑ:ÝBFÄ)Á+Ä+Õ3°JÑ?Ø�ða Tøõb ð 	ð 	ð 	ØˆJˆJˆJˆJˆJˆJøøøøð	øøøð  ð 4ñ 4ˆ	Ø×Ò˜sÑ#Ô# iÑ/ˆð2	Ý”| C°À"ÕMeÑMgÔMgÐhÑhÔhˆHØ×%Ò%Ñ'Ô'Ð'Ø—m’m‘o”oˆGØ/1ˆEØ Ÿš V¨RÑ0Ô0ð ;ð ;�Ý! %­Ñ.Ô.ð ØØ Ÿ9š9 T™?œ?�Øð ØØ)/°·²¸6À8Ñ1LÔ1LÐ(M�Ý!8¸Ñ!?Ô!?�Ø!Ð-Ø.<�EÐ*Ñ+Ý(FÀuÑ(MÔ(MÐ%Ø(Ð4Ø5J�EÐ1Ñ2Ý*¨5Ñ1Ô1�Øð /Ø'.�E˜)Ñ$Ý" 5¨(°EÑ:Ô:Ð:Ð:õ ð ð à Ÿš V¨RÑ0Ô0ðñ ô ñ ô ˆKð ð ðà$×+Ò+¨CÑ0Ô0×8Ò8¸ÀÑCÔC�DÝ6Ñ8Ô8�GÝ!)¤¨d°[Ñ.@È'Ð[\ÐelÐ!mÑ!mÔ!m�JØ%œ=ð oÝ%-¤\°$¸±/È7Ð\]ÐfmÐ%nÑ%nÔ%n˜
Ø!”}ð IØ *§¢Ñ 1Ô 1˜Ø',§y¢yÐ1NÐPRÑ'SÔ'S˜Ø ,× 0Ò 0°Ñ 9Ô 9˜Ø&+§i¢i°¸rÑ&BÔ&B˜Ø ð I [ð I°[ÀEÐ5IÐ5IØCH˜E +Ô.Ð/?Ñ@øøÝ ð ð ð Ø�Dðøøøð :?Õ*¨:Ñ6Ý>B¼i¹k¼kÕ/°
Ñ;ØˆLˆLˆLøÝð 	ð 	ð 	ØˆJˆJˆJˆJˆJ‰Jøøøøð	øøøð ð bÝ�ŠÐHÈ*ÐV`ÑaÔaÐaØ13Õ" :Ñ.Ý6:´i±k´kÕ'¨
Ñ3Ø€IsW   Ã1I6M) Í)
M?Í3M:Í:M?Î D/W-ÓC#V4Ö3W-Ö4
WÖ>W-× W×)W-×-
X×7W?×?Xc                  ó(   — ddl m}   | ¦   «         dz  S )z8Return path to the persistent context length cache file.r   ©Úget_hermes_homezcontext_length_cache.yaml)Úhermes_constantsrl  rk  s    r   Ú_get_context_cache_pathrn  Á  s(   € à0Ð0Ð0Ð0Ð0Ð0Øˆ?ÑÔÐ:Ñ:Ð:r   c                  óZ  — t          ¦   «         } |                      ¦   «         si S 	 t          | ¦  «        5 }t          j        |¦  «        pi }ddd¦  «         n# 1 swxY w Y   |                     di ¦  «        S # t          $ r'}t                               d|¦  «         i cY d}~S d}~ww xY w)z:Load the model+provider -> context_length cache from disk.NÚcontext_lengthsz'Failed to load context length cache: %s)	rn  ÚexistsÚopenÚyamlÚ	safe_loadræ   r¿   rC  rD  )r   Úfrí   rI  s       r   Ú_load_context_cacherv  Ç  sñ   € å"Ñ$Ô$€DØ�;Š;‰=Œ=ð Øˆ	ðÝ�$‰ZŒZð 	+˜1Ý”> !Ñ$Ô$Ð*¨ˆDð	+ð 	+ð 	+ñ 	+ô 	+ð 	+ð 	+ð 	+ð 	+ð 	+ð 	+øøøð 	+ð 	+ð 	+ð 	+à�xŠxÐ)¨2Ñ.Ô.Ð.øÝð ð ð Ý�ŠÐ>ÀÑBÔBÐBØˆ	ˆ	ˆ	ˆ	ˆ	ˆ	øøøøðøøøs@   ¦A9 µAÁA9 ÁAÁA9 ÁAÁ A9 Á9
B*ÂB%ÂB*Â%B*Úlengthc                 óê  — | › d|› �}t          ¦   «         }|                     |¦  «        |k    rdS |||<   t          ¦   «         }	 |j                             dd¬¦  «         t          |d¦  «        5 }t          j        d|i|d¬¦  «         ddd¦  «         n# 1 swxY w Y   t           	                    d	||d
›¦  «         dS # t          $ r&}t                               d|¦  «         Y d}~dS d}~ww xY w)z¿Persist a discovered context length for a model+provider combo.

    Cache key is ``model@base_url`` so the same model name served from
    different providers can have different limits.
    ú@NT©ÚparentsÚexist_okÚwrp  F©Údefault_flow_stylez%Cached context length %s -> %s tokensrü   z'Failed to save context length cache: %s)rv  ræ   rn  ÚparentÚmkdirrr  rs  ÚdumprC  Úinfor¿   rD  )rZ   r‰   rw  r  r1  r   ru  rI  s           r   Úsave_context_lengthr„  Õ  si  € ð Ð
Ð
�XÐ
Ð
€CÝÑ!Ô!€EØ‡y‚y��~„~˜ÒÐØˆØ€Eˆ#�JÝ"Ñ$Ô$€DðCØŒ×Ò $°ÐÑ6Ô6Ð6Ý�$˜‰_Œ_ð 	O ÝŒIÐ(¨%Ð0°!ÈÐNÑNÔNÐNð	Oð 	Oð 	Oñ 	Oô 	Oð 	Oð 	Oð 	Oð 	Oð 	Oð 	Oøøøð 	Oð 	Oð 	Oð 	Oå�ŠÐ;¸SÀVÀ-À-ÑPÔPÐPÐPÐPøÝð Cð Cð CÝ�ŠÐ>ÀÑBÔBÐBÐBÐBÐBÐBÐBÐBøøøøðCøøøs<   Á,C Á1BÂC ÂBÂC ÂBÂ!C Ã
C2ÃC-Ã-C2c                 óV   — | › d|› �}t          ¦   «         }|                     |¦  «        S )zBLook up a previously discovered context length for model+provider.ry  )rv  ræ   )rZ   r‰   r  r1  s       r   Úget_cached_context_lengthr†  ê  s0   € àÐ
Ð
�XÐ
Ð
€CÝÑ!Ô!€EØ�9Š9�S‰>Œ>Ðr   c                 ó„  — | › d|› �}t          ¦   «         }||vrdS ||= t          ¦   «         }	 |j                             dd¬¦  «         t	          |d¦  «        5 }t          j        d|i|d¬¦  «         ddd¦  «         dS # 1 swxY w Y   dS # t          $ r'}t           	                    d	||¦  «         Y d}~dS d}~ww xY w)
zCDrop a stale cache entry so it gets re-resolved on the next lookup.ry  NTrz  r}  rp  Fr~  z6Failed to invalidate context length cache entry %s: %s)
rv  rn  r€  r�  rr  rs  r‚  r¿   rC  rD  )rZ   r‰   r  r1  r   ru  rI  s          r   Ú!_invalidate_cached_context_lengthrˆ  ñ  sO  € àÐ
Ð
�XÐ
Ð
€CÝÑ!Ô!€EØ
�%ÐÐØˆØˆcˆ
Ý"Ñ$Ô$€DðWØŒ×Ò $°ÐÑ6Ô6Ð6Ý�$˜‰_Œ_ð 	O ÝŒIÐ(¨%Ð0°!ÈÐNÑNÔNÐNð	Oð 	Oð 	Oñ 	Oô 	Oð 	Oð 	Oð 	Oð 	Oð 	Oð 	Oð 	Oøøøð 	Oð 	Oð 	Oð 	Oð 	Oð 	Oøåð Wð Wð WÝ�ŠÐMÈsÐTUÑVÔVÐVÐVÐVÐVÐVÐVÐVøøøøðWøøøs;   ®,B ÁBÁ4B ÂBÂB ÂBÂ	B Â
B?ÂB:Â:B?Úcurrent_lengthc                 ó.   — t           D ]}|| k     r|c S ŒdS )z@Return the next lower probe tier, or None if already at minimum.N)ÚCONTEXT_PROBE_TIERS)r‰  Útiers     r   Úget_next_probe_tierr�    s/   € å#ð ð ˆØ�.Ò Ð ØˆKˆKˆKð !àˆ4r   Ú	error_msgc                 óÚ   — |                       ¦   «         }g d¢}|D ]O}t          j        ||¦  «        }|r6t          |                     d¦  «        ¦  «        }d|cxk    rdk    rn ŒK|c S ŒPdS )a?  Try to extract the actual context limit from an API error message.

    Many providers include the limit in their error text, e.g.:
      - "maximum context length is 32768 tokens"
      - "context_length_exceeded: 131072"
      - "Maximum context size 32768 exceeded"
      - "model's max context length is 65536"
    )zY(?:max(?:imum)?|limit)\s*(?:context\s*)?(?:length|size|window)?\s*(?:is|of|:)?\s*(\d{4,})z:context\s*(?:length|size|window)\s*(?:is|of|:)?\s*(\d{4,})z)(\d{4,})\s*(?:token)?\s*(?:context|limit)z">\s*(\d{4,})\s*(?:max|limit|token)z(\d{4,})\s*(?:max(?:imum)?)\br^   r÷   rø   N©rb   ÚreÚsearchrÍ   Úgroup)rŽ  Úerror_lowerÚpatternsÚpatternrd   Úlimits         r   Úparse_context_limit_from_errorr˜  	  s–   € ð —/’/Ñ#Ô#€Kðð ð €Hð ð ð ˆÝ”	˜' ;Ñ/Ô/ˆØð 	Ý˜Ÿš A™œÑ'Ô'ˆEà�uÐ*Ð*Ò*Ð* 
Ò*Ð*Ð*Ð*Ð*Ø���øØˆ4r   c                 óæ   — |                       ¦   «         }d|v od|v pd|v }|sdS g d¢}|D ]E}t          j        ||¦  «        }|r,t          |                     d¦  «        ¦  «        }|dk    r|c S ŒFdS )u#  Detect an "output cap too large" error and return how many output tokens are available.

    Background â€” two distinct context errors exist:
      1. "Prompt too long"  â€” the INPUT itself exceeds the context window.
           Fix: compress history and/or halve context_length.
      2. "max_tokens too large" â€” input is fine, but input + requested_output > window.
           Fix: reduce max_tokens (the output cap) for this call.
           Do NOT touch context_length â€” the window hasn't shrunk.

    Anthropic's API returns errors like:
      "max_tokens: 32768 > context_window: 200000 - input_tokens: 190000 = available_tokens: 10000"

    Returns the number of output tokens that would fit (e.g. 10000 above), or None if
    the error does not look like a max_tokens-too-large error.
    r‡   Úavailable_tokenszavailable tokensN)zavailable_tokens[:\s]+(\d+)zavailable\s+tokens[:\s]+(\d+)z=\s*(\d+)\s*$r^   r�  )rŽ  r”  Úis_output_cap_errorr•  r–  rd   Útokenss          r   Ú(parse_available_output_tokens_from_errorr�  %  s´   € ð  —/’/Ñ#Ô#€Kð 	˜Ð#ð 	UØ ;Ð.ÐSÐ2DÈÐ2Sð ð ð Øˆtðð ð €Hð ð ð ˆÝ”	˜' ;Ñ/Ô/ˆØð 	Ý˜Ÿš Q™œÑ(Ô(ˆFØ˜Š{ˆ{Ø���øØˆ4r   Úcandidate_idÚlookup_modelc                 ób   — | |k    rdS d| v r"|                       dd¦  «        d         |k    rdS dS )a  Return True if *candidate_id* (from server) matches *lookup_model* (configured).

    Supports two forms:
    - Exact match:  "nvidia-nemotron-super-49b-v1" == "nvidia-nemotron-super-49b-v1"
    - Slug match:   "nvidia/nvidia-nemotron-super-49b-v1" matches "nvidia-nemotron-super-49b-v1"
                    (the part after the last "/" equals lookup_model)

    This covers LM Studio's native API which stores models as "publisher/slug"
    while users typically configure only the slug after the "local:" prefix.
    TrŒ   r^   F)Úrsplit)rž  rŸ  s     r   Ú_model_id_matchesr¢  P  sH   € ð �|Ò#Ð#Øˆtà
ˆlÐÐ˜|×2Ò2°3¸Ñ:Ô:¸1Ô=ÀÒMÐMØˆtØˆ5r   c                 ó@  — ddl }t          | ¦  «        }|                     d¦  «        }|                     d¦  «        r
|dd…         }	 t	          ||¬¦  «        }n# t
          $ r Y dS w xY w|dk    rdS t          |¦  «        }	 |                     d|¬	¦  «        5 }|                     |› d
�d|i¬¦  «        }	|	j	        dk    r	 ddd¦  «         dS |	 
                    ¦   «         }
|
                     dd¦  «        }d|v r‰|                     d¦  «        D ]s}d|v rm|                     ¦   «                              ¦   «         }t          |¦  «        dk    r4	 t          |d         ¦  «        c cddd¦  «         S # t           $ r Y Œow xY wŒt|
                     di ¦  «        }|                     ¦   «         D ]B\  }}d|v r9t%          |t          t&          f¦  «        rt          |¦  «        c cddd¦  «         S ŒC	 ddd¦  «         n# 1 swxY w Y   n# t
          $ r Y nw xY wdS )ay  Query an Ollama server for the model's context length.

    Returns the model's maximum context from GGUF metadata via ``/api/show``,
    or the explicit ``num_ctx`` from the Modelfile if set.  Returns None if
    the server is unreachable or not Ollama.

    This is the value that should be passed as ``num_ctx`` in Ollama chat
    requests to override the default 2048.
    r   NrŒ   rÕ   rÖ   rL  rA   ç      @r×   ú	/api/showr=  ©rè   rÛ   Ú
parametersr‹   Únum_ctxÚ
é   éÿÿÿÿÚ
model_inforz   )rä   rh   r�   r°   rî   r¿   r–   rå   Úpostrç   rè   ræ   r`   ra   rÌ   rÍ   rË   r¦   rÈ   Úfloat)rZ   r‰   r�   rä   r6  rê   Úserver_typerÙ   rë   Úresprí   ÚparamsÚlinerÐ   r¬  r  rï   s                    r   Úquery_ollama_num_ctxr³  c  s  € ð €L€L€Lå'¨Ñ.Ô.€JØ—’ Ñ%Ô%€JØ×Ò˜5Ñ!Ô!ð %Ø   ”_ˆ
ðÝ.¨xÀÐIÑIÔIˆˆøÝð ð ð Øˆtˆtðøøøà�hÒÐØˆtå˜GÑ$Ô$€GðØ�\Š\ #¨wˆ\Ñ7Ô7ð 	&¸6Ø—;’; *Ð7Ð7Ð7¸vÀzÐ>R�;ÑSÔSˆDØÔ 3Ò&Ð&Øð	&ð 	&ð 	&ñ 	&ô 	&ð 	&ð 	&ð 	&ð —9’9‘;”;ˆDð —X’X˜l¨BÑ/Ô/ˆFØ˜FÐ"Ð"Ø"ŸLšL¨Ñ.Ô.ð %ð %�DØ  DÐ(Ð(Ø $§
¢
¡¤× 2Ò 2Ñ 4Ô 4˜Ý˜u™:œ:¨š?˜?ð%Ý'*¨5°¬9¡~¤~Ð 5Ð 5ð	&ð 	&ð 	&ð 	&ñ 	&ô 	&ð 	&ð 	&øõ $.ð %ð %ð %Ø $ ð%øøøøð Ÿš ,°Ñ3Ô3ˆJØ(×.Ò.Ñ0Ô0ð &ð &‘
��UØ# sÐ*Ð*­z¸%Å#ÅuÀÑ/NÔ/NÐ*Ý˜u™:œ:Ð%Ð%ð-	&ð 	&ð 	&ð 	&ñ 	&ô 	&ð 	&ð 	&øð(&ð)	&ð 	&ð 	&ñ 	&ô 	&ð 	&ð 	&ð 	&ð 	&ð 	&ð 	&øøøð 	&ð 	&ð 	&ð 	&øøõ. ð ð ð Øˆðøøøàˆ4sŒ   Á	A Á
A)Á(A)ÂH Â)HÃH ÃBHÅE7Å(HÅ*H Å7
FÆHÆFÆA#HÇ'H Ç4HÇ6H ÈHÈH È	HÈ
H È
HÈHc                 óv
  — ddl }t          | ¦  «        } |                     d¦  «        }|                     d¦  «        r
|dd…         }t	          |¦  «        }	 t          ||¬¦  «        }n# t          $ r d}Y nw xY w	 |                     d|¬¦  «        5 }|d	k    �rL|                     |› d
�d| i¬¦  «        }|j	        dk    �r$| 
                    ¦   «         }	|	                     dd¦  «        }
d|
v r‰|
                     d¦  «        D ]s}d|v rm|                     ¦   «                              ¦   «         }t          |¦  «        dk    r4	 t          |d         ¦  «        c cddd¦  «         S # t           $ r Y Œow xY wŒt|	                     di ¦  «        }|                     ¦   «         D ]B\  }}d|v r9t%          |t          t&          f¦  «        rt          |¦  «        c cddd¦  «         S ŒC|dk    �r�|                     |› d�¦  «        }|j	        dk    �r]| 
                    ¦   «         }	|	                     dg ¦  «        D �]1}t)          |                     dd¦  «        | ¦  «        s$t)          |                     dd¦  «        | ¦  «        ræ|                     dg ¦  «        D ]j}|                     di ¦  «        }|                     d¦  «        }|r;t%          |t          t&          f¦  «        rt          |¦  «        c c cddd¦  «         S Œk|                     d¦  «        p|                     d¦  «        }|r9t%          |t          t&          f¦  «        rt          |¦  «        c cddd¦  «         S �Œ3|                     |› d| › �¦  «        }|j	        dk    rŒ| 
                    ¦   «         }	|	                     d¦  «        p)|	                     d¦  «        p|	                     d ¦  «        }|r7t%          |t          t&          f¦  «        rt          |¦  «        cddd¦  «         S |                     |› d!�¦  «        }|j	        dk    rÍ| 
                    ¦   «         }	|	                     d"g ¦  «        }|D ] }t)          |                     dd¦  «        | ¦  «        rz|                     d¦  «        p)|                     d¦  «        p|                     d ¦  «        }|r9t%          |t          t&          f¦  «        rt          |¦  «        c cddd¦  «         S Œ¡ddd¦  «         n# 1 swxY w Y   n# t          $ r Y nw xY wdS )#z4Query a local server for the model's context length.r   NrŒ   rÕ   rÖ   rL  r¤  r×   rA   r¥  r=  r¦  rÛ   r§  r‹   r¨  r©  rª  r«  r¬  rz   rÜ   rÚ   rÝ   r  r;  rN  rO  r|   z/v1/models/r~   r‡   z
/v1/modelsrí   )rä   rh   r�   r°   r–   rî   r¿   rå   r­  rç   rè   ræ   r`   ra   rÌ   rÍ   rË   r¦   rÈ   r®  r¢  )rZ   r‰   r�   rä   rê   rÙ   r¯  rë   r°  rí   r±  r²  rÐ   r¬  r  rï   rR  r]  r^  r_  Úmodels_lists                        r   Ú_query_local_context_lengthr¶  š  sš  € à€L€L€Lõ # 5Ñ)Ô)€Eð —’ Ñ%Ô%€JØ×Ò˜5Ñ!Ô!ð %Ø   ”_ˆ
å˜GÑ$Ô$€GðÝ.¨xÀÐIÑIÔIˆˆøÝð ð ð ØˆˆˆðøøøðHØ�\Š\ #¨wˆ\Ñ7Ô7ð E	,¸6à˜hÒ&Ñ&Ø—{’{ jÐ#;Ð#;Ð#;À6È5À/�{ÑRÔR�ØÔ# sÒ*Ñ*ØŸ9š9™;œ;�Dð "ŸXšX l°BÑ7Ô7�FØ  FÐ*Ð*Ø$*§L¢L°Ñ$6Ô$6ð -ð -˜DØ(¨DÐ0Ð0Ø(,¯
ª
©¬×(:Ò(:Ñ(<Ô(< Ý#& u¡:¤:°¢? ?ð%-Ý/2°5¸´9©~¬~Ð(=Ð(=ð'E	,ð E	,ð E	,ð E	,ñ E	,ô E	,ð E	,ð E	,øõ( ,6ð %-ð %-ð %-Ø(,¨ð%-øøøøð "&§¢¨,¸Ñ!;Ô!;�JØ&0×&6Ò&6Ñ&8Ô&8ð .ð .™
˜˜UØ+¨sÐ2Ð2µzÀ%Í#ÍuÈÑ7VÔ7VÐ2Ý#& u¡:¤:Ð-Ð-ð5E	,ð E	,ð E	,ð E	,ñ E	,ô E	,ð E	,ð E	,øðB ˜kÒ)Ñ)Ø—z’z ZÐ"?Ð"?Ð"?Ñ@Ô@�ØÔ# sÒ*Ñ*ØŸ9š9™;œ;�DØ!ŸXšX h°Ñ3Ô3ð 0ñ 0˜Ý,¨Q¯UªU°5¸"Ñ-=Ô-=¸uÑEÔEð 
0ÕIZÐ[\×[`Ò[`ÐaeÐgiÑ[jÔ[jÐlqÑIrÔIrð 
0à()¯ªÐ.@À"Ñ(EÔ(Eð 4ð 4 Ø&*§h¢h¨x¸Ñ&<Ô&< Ø&)§g¢gÐ.>Ñ&?Ô&? Ø#&ð !4­:°c½CÅ¸<Ñ+HÔ+Hð !4Ý+.¨s©8¬8 O O O OðYE	,ð E	,ð E	,ð E	,ñ E	,ô E	,ð E	,ð E	,øð\ #$§%¢%Ð(<Ñ"=Ô"=Ð"XÀÇÂÐGWÑAXÔAX˜CØ"ð 0¥z°#½½U°|Ñ'DÔ'Dð 0Ý'*¨3¡x¤x  ðaE	,ð E	,ð E	,ð E	,ñ E	,ô E	,ð E	,ð E	,ùðf —:’: Ð?Ð?¸Ð?Ð?Ñ@Ô@ˆDØÔ 3Ò&Ð&Ø—y’y‘{”{�à—h’h˜Ñ/Ô/Ðg°4·8²8Ð<LÑ3MÔ3MÐgÐQU×QYÒQYÐZfÑQgÔQg�Øð $�: c­Cµ¨<Ñ8Ô8ð $Ý˜s™8œ8ðsE	,ð E	,ð E	,ð E	,ñ E	,ô E	,ð E	,ð E	,ðz —:’: Ð7Ð7Ð7Ñ8Ô8ˆDØÔ 3Ò&Ð&Ø—y’y‘{”{�Ø"Ÿhšh v¨rÑ2Ô2�Ø$ð ,ð ,�AÝ(¨¯ª¨t°R©¬¸%Ñ@Ô@ð ,ØŸeše OÑ4Ô4Ðf¸¿ºÐ>NÑ8OÔ8OÐfÐST×SXÒSXÐYeÑSfÔSf˜Øð ,¥:¨cµC½°<Ñ#@Ô#@ð ,Ý#& s¡8¤8˜O˜OðKE	,ð E	,ð E	,ð E	,ñ E	,ô E	,ð E	,ð E	,øð E	,ð E	,ð E	,ñ E	,ô E	,ð E	,ð E	,ð E	,ð E	,ð E	,ð E	,øøøð E	,ð E	,ð E	,ð E	,øøõL ð ð ð Øˆðøøøð ˆ4s´   ÁA* Á*A9Á8A9Á=T) ÂB2TÅE*ÅTÅT) Å*
E7Å4TÅ6E7Å7A#TÇT) Ç'DTË;T) ÌATÍ!T) Í.B&TÐT) Ð!C"TÔT) ÔTÔT) ÔT!Ô!T) Ô$T!Ô%T) Ô)
T6Ô5T6c                 ó.   — |                       dd¦  «        S )zÓNormalize version separators for matching.

    Nous uses dashes: claude-opus-4-6, claude-sonnet-4-5
    OpenRouter uses dots: claude-opus-4.6, claude-sonnet-4.5
    Normalize both to dashes for comparison.
    r³   Ú-)rý   )rZ   s    r   Ú_normalize_model_versionr¹  û  s   € ð �=Š=˜˜cÑ"Ô"Ð"r   c                 ór  — |r|                      d¦  «        rdS 	 |                     d¦  «        }|                     d¦  «        r
|dd…         }|› d�}|ddœ}t          j        ||d	t          ¦   «         ¬
¦  «        }|j        dk    rdS |                     ¦   «         }|                     dg ¦  «        D ]O}|                     d¦  «        | k    r4|                     d¦  «        }	t          |	t          ¦  «        r
|	dk    r|	c S ŒPn2# t          $ r%}
t                               d|
¦  «         Y d}
~
nd}
~
ww xY wdS )z¸Query Anthropic's /v1/models endpoint for context length.

    Only works with regular ANTHROPIC_API_KEY (sk-ant-api*).
    OAuth tokens (sk-ant-oat*) from Claude Code return 401.
    z
sk-ant-oatNrŒ   rÕ   rÖ   z/v1/models?limit=1000z
2023-06-01)z	x-api-keyzanthropic-versionrµ   rM  rÛ   rí   r;  r   r   z%Anthropic /v1/models query failed: %s)r_   r�   r°   rA  ræ   r   rç   rè   rÈ   rÍ   r¿   rC  rD  )rZ   r‰   r�   rd  rÎ   rÙ   r°  rí   rR  r_  rI  s              r   Ú_query_anthropic_context_lengthr»    sz  € ð ð �g×(Ò(¨Ñ6Ô6ð ØˆtðAØ�Š˜sÑ#Ô#ˆØ�=Š=˜ÑÔð 	Ø˜˜˜”9ˆDØÐ,Ð,Ð,ˆà Ø!-ð
ð 
ˆõ Œ|˜C¨¸"ÕE]ÑE_ÔE_Ð`Ñ`Ô`ˆØÔ˜sÒ"Ð"Ø�4Ø�yŠy‰{Œ{ˆØ—’˜& "Ñ%Ô%ð 	ð 	ˆAØ�uŠu�T‰{Œ{˜eÒ#Ð#Ø—e’eÐ.Ñ/Ô/�Ý˜c¥3Ñ'Ô'ð ¨C°!ªG¨GØ�J�J�Jøð		øõ
 ð Að Að AÝ�ŠÐ<¸aÑ@Ô@Ð@Ð@Ð@Ð@Ð@Ð@øøøøðAøøøàˆ4s%   ›A-D Â
A8D ÄD Ä
D4ÄD/Ä/D4i€& )	zgpt-5.1-codex-maxzgpt-5.1-codex-minizgpt-5.3-codexzgpt-5.2-codexrr   rp   rs   zgpt-5.2rt   Ú_CODEX_OAUTH_CONTEXT_FALLBACKÚ_codex_oauth_context_cacheg        Ú_codex_oauth_context_cache_timeÚaccess_tokenc                 ó0  — t          j         ¦   «         }t          r|t          z
  t          k     rt          S 	 t	          j        ddd| › �idt          ¦   «         ¬¦  «        }|j        dk    r"t           	                    d|j        ¦  «         i S | 
                    ¦   «         }n4# t          $ r'}t           	                    d|¦  «         i cY d	}~S d	}~ww xY wt          |t          ¦  «        r|                     d
g ¦  «        ng }i }|D ]‰}t          |t          ¦  «        sŒ|                     d¦  «        }|                     d¦  «        }	t          |t          ¦  «        r2t          |	t          ¦  «        r|	dk    r|	||                     ¦   «         <   ŒŠ|r|a|a|S )ak  Probe the ChatGPT Codex /models endpoint for per-slug context windows.

    Codex OAuth imposes its own context limits that differ from the direct
    OpenAI API (e.g. gpt-5.5 is 1.05M on the API, 272K on Codex). The
    `context_window` field in each model entry is the authoritative source.

    Returns a ``{slug: context_window}`` dict. Empty on failure.
    zAhttps://chatgpt.com/backend-api/codex/models?client_version=1.0.0r’   r“   rµ   rM  rÛ   zHCodex /models probe returned HTTP %s; falling back to hardcoded defaultszCodex /models probe failed: %sNrÝ   Úslugr{   r   )r?  r½  r¾  Ú_CODEX_OAUTH_CONTEXT_CACHE_TTLrA  ræ   r   rç   rC  rD  rè   r¿   rÈ   rñ   r”   rÍ   ra   )
r¿  Únowr°  rí   ra  Úentriesrÿ   rö   rÁ  r_  s
             r   Ú"_fetch_codex_oauth_context_lengthsrÅ  >  s¾  € õ Œ)‰+Œ+€Cå"ð*àÕ1Ñ1Õ4RÒRÐRå)Ð)ðÝŒ|ØOØ$Ð&>°Ð&>Ð&>Ð?ØÝ+Ñ-Ô-ð	
ñ 
ô 
ˆð Ô˜sÒ"Ð"Ý�LŠLØZØÔ ñô ð ð ˆIØ�yŠy‰{Œ{ˆˆøÝð ð ð Ý�ŠÐ5°sÑ;Ô;Ð;Øˆ	ˆ	ˆ	ˆ	ˆ	ˆ	øøøøðøøøõ )3°4½Ñ(>Ô(>ÐFˆd�hŠh�x Ñ$Ô$Ð$ÀB€GØ€FØð 'ð 'ˆÝ˜$¥Ñ%Ô%ð 	ØØ�xŠx˜ÑÔˆØ�hŠhÐ'Ñ(Ô(ˆÝ�d�CÑ Ô ð 	'¥Z°µSÑ%9Ô%9ð 	'¸cÀAºg¸gØ#&ˆF�4—:’:‘<”<Ñ øàð .Ø%+Ð"Ø*-Ð'Ø€Ms$   ¶AB! ÂB! Â!
CÂ+CÃCÃCc                 ó¶  — t          | ¦  «                             ¦   «         }|sdS |ret          |¦  «        }||v r||         S |                     ¦   «         }|                     ¦   «         D ]!\  }}|                     ¦   «         |k    r|c S Œ"|                     ¦   «         }t          t                               ¦   «         d„ d¬¦  «        D ]\  }}||v r|c S ŒdS )zÒResolve a Codex OAuth model's real context window.

    Prefers a live probe of chatgpt.com/backend-api/codex/models (when we
    have a bearer token), then falls back to ``_CODEX_OAUTH_CONTEXT_FALLBACK``.
    Nc                 ó,   — t          | d         ¦  «        S ©Nr   ©rÌ   ©Úxs    r   ú<lambda>z5_resolve_codex_oauth_context_length.<locals>.<lambda>Š  s   € ½SÀÀ1Ä¹Y¼Y€ r   T©r  Úreverse)rh   ra   rÅ  rb   r¦   Úsortedr¼  )rZ   r¿  Ú
model_bareÚliveÚmodel_lowerrÁ  r_  s          r   Ú#_resolve_codex_oauth_context_lengthrÓ  q  s  € õ (¨Ñ.Ô.×4Ò4Ñ6Ô6€JØð Øˆtàð Ý1°,Ñ?Ô?ˆØ˜ÐÐØ˜
Ô#Ð#à ×&Ò&Ñ(Ô(ˆØŸš™œð 	ð 	‰IˆD�#Ø�zŠz‰|Œ|˜{Ò*Ð*Ø�
�
�
ð +ð ×"Ò"Ñ$Ô$€KÝÝ%×+Ò+Ñ-Ô-Ð3FÐ3FÐPTðñ ô ð ð ‰	ˆˆcð �;ÐÐØˆJˆJˆJð ð ˆ4r   c                 óÎ  — t          ¦   «         }| |v r||                               d¦  «        S t          | ¦  «                             ¦   «         }|                     ¦   «         D ]�\  }}d|v r|                     dd¦  «        d         n|}|                     ¦   «         |                      ¦   «         k    s%t          |¦  «                             ¦   «         |k    r|                     d¦  «        c S ŒŽ|                      ¦   «         }|                     ¦   «         D ]Ë\  }}d|v r|                     dd¦  «        d         n|}|                     ¦   «         |ft          |¦  «                             ¦   «         |ffD ]j\  }}|                     |¦  «        rPt          |¦  «        t          |¦  «        k    s|t          |¦  «                 dv r|                     d¦  «        c c S ŒkŒÌdS )u  Resolve Nous Portal model context length via OpenRouter metadata.

    Nous model IDs are bare (e.g. 'claude-opus-4-6') while OpenRouter uses
    prefixed IDs (e.g. 'anthropic/claude-opus-4.6'). Try suffix matching
    with version normalization (dotâ†”dash).
    rz   rŒ   r^   z-:.N)rJ  ræ   r¹  rb   r¦   r`   r_   rÌ   )	rZ   Úmetadatar�   Úor_idr3  ÚbarerÒ  rb  Úquerys	            r   Ú_resolve_nous_context_lengthrÙ  ’  sé  € õ $Ñ%Ô%€Hà�ÐÐØ˜Œ×"Ò"Ð#3Ñ4Ô4Ð4å)¨%Ñ0Ô0×6Ò6Ñ8Ô8€Jà ŸšÑ(Ô(ð /ð /‰ˆˆuØ),°¨¨ˆu�{Š{˜3 Ñ"Ô" 1Ô%Ð%¸5ˆØ�:Š:‰<Œ<˜5Ÿ;š;™=œ=Ò(Ð(Õ,DÀTÑ,JÔ,J×,PÒ,PÑ,RÔ,RÐV`Ò,`Ð,`Ø—9’9Ð-Ñ.Ô.Ð.Ð.Ð.ð -að
 —+’+‘-”-€KØ ŸšÑ(Ô(ð 3ð 3‰ˆˆuØ),°¨¨ˆu�{Š{˜3 Ñ"Ô" 1Ô%Ð%¸5ˆØ"&§*¢*¡,¤,°Ð!<Õ?WÐX\Ñ?]Ô?]×?cÒ?cÑ?eÔ?eÐgqÐ>rÐ sð 	3ð 	3ÑˆI�uØ×#Ò# EÑ*Ô*ð 3Ý�I‘”¥# e¡*¤*Ò,Ð,°	½#¸e¹*¼*Ô0EÈÐ0NÐ0Nà—y’yÐ!1Ñ2Ô2Ð2Ð2Ð2Ð2Ð2øð		3ð ˆ4r   Úconfig_context_lengthrª   Úcustom_providersc                 ó  — |�t          |t          ¦  «        r|dk    r|S |r.|r,| r*	 ddlm}  || ||¬¦  «        }|r|S n# t          $ r Y nw xY wt          | ¦  «        } |rPt          | |¦  «        }|�>|dk    r6|dk    r0t                               d| ||d›¦  «         t          | |¦  «         n|S |d	k    s4|rTt          |¦  «                             d
¦  «        r2t          |d¦  «        r"	 ddlm}	  |	| ¦  «        S # t          $ r Y nw xY wt!          |¦  «        �rDt#          |¦  «        �s4t%          ||¬¦  «        }
|
                     | ¦  «        }|sht)          |
¦  «        dk    r/t+          t-          |
                     ¦   «         ¦  «        ¦  «        }n&|
                     ¦   «         D ]\  }}| |v s|| v r|} nŒ|r,|                     d¦  «        }t          |t          ¦  «        r|S t#          |¦  «        sgt3          |¦  «        r-t5          | ||¬¦  «        }|r|dk    rt7          | ||¦  «         |S t                               d| |t8          d›¦  «         t8          S |dk    s|r*t          |¦  «        dk    rt;          | |pd|¦  «        }|r|S |}|r|dv r|rt=          |¦  «        }|r|}|dv r)	 ddlm }  || |¬¦  «        }|r|S n# t          $ r Y nw xY w|dk    rtC          | ¦  «        }|r|S |dk    r*tE          | |pd¬¦  «        }|r|rt7          | ||¦  «         |S |rddl#m$}  ||| ¦  «        }|r|S tK          ¦   «         }| |v r!||                               dt8          ¦  «        S |  &                    ¦   «         }tO          tP                               ¦   «         d„ d¬¦  «        D ]\  }}||v r|c S Œ|r<t3          |¦  «        r-t5          | ||¬¦  «        }|r|dk    rt7          | ||¦  «         |S t8          S )a©  Get the context length for a model.

    Resolution order:
    0. Explicit config override (model.context_length or custom_providers per-model)
    1. Persistent cache (previously discovered via probing)
    1b. AWS Bedrock static table (must precede custom-endpoint probe)
    2. Active endpoint metadata (/models for explicit custom endpoints)
    3. Local server query (for local endpoints)
    4. Anthropic /v1/models API (API-key users only, not OAuth)
    5. OpenRouter live API metadata
    6. Nous suffix-match via OpenRouter cache
    7. models.dev registry lookup (provider-aware)
    8. Thin hardcoded defaults (broad family patterns)
    9. Default fallback (128K)
    Nr   )Ú"get_custom_provider_context_length)rZ   r‰   rÛ  rV   rq   zaDropping stale Codex cache entry %s@%s -> %s (pre-fix value); re-resolving via live /models proberü   Úbedrockzbedrock-runtime.zamazonaws.com)Úget_bedrock_context_lengthrL  r^   rz   u‘   Could not detect context length for model %r at %s â€” defaulting to %s tokens (probe-down). Set model.context_length in config.yaml to override.rN   r    zhttps://api.anthropic.com)rP   r<   )rF   rR   rW   )Úget_copilot_model_contextr5   r‹   )r¿  )Úlookup_models_dev_contextc                 ó,   — t          | d         ¦  «        S rÈ  rÉ  rÊ  s    r   rÌ  z*get_model_context_length.<locals>.<lambda>r  s   € µs¸1¸Q¼4±y´y€ r   TrÍ  ))rÈ   rÍ   Úhermes_cli.configrÝ  r¿   rh   r†  rC  rƒ  rˆ  r
   r_   r	   Úagent.bedrock_adapterrß  ÚImportErrorrž   r­   ri  ræ   rÌ   ÚnextÚiterrò   r¦   rÓ   r¶  r„  ÚDEFAULT_FALLBACK_CONTEXTr»  r«   Úhermes_cli.modelsrà  rÙ  rÓ  Úagent.models_devrá  rJ  rb   rÏ  ÚDEFAULT_CONTEXT_LENGTHS)rZ   r‰   r�   rÚ  rª   rÛ  rÝ  Úcp_ctxrX  rß  Úendpoint_metadataÚmatchedr  r3  rz   Ú	local_ctxr_  Úeffective_providerÚinferredrà  Ú	codex_ctxrá  rÕ  rÒ  Údefault_modelrw  s                             r   Úget_model_context_lengthrô  ³  sî  € ð0 Ð(­ZÐ8MÍsÑ-SÔ-SÐ(ÐXmÐpqÒXqÐXqØ$Ð$ð ð ˜Hð ¨ð ð
	ØLÐLÐLÐLÐLÐLØ7Ð7ØØ!Ø!1ðñ ô ˆFð
 ð Ø�ðøåð 	ð 	ð 	ØˆDð	øøøõ # 5Ñ)Ô)€Eð ð Ý*¨5°(Ñ;Ô;ˆØÐð ˜>Ò)Ð)¨f¸Ò.?Ð.?Ý—’ð:à˜8¨ ] ]ñô ð õ
 2°%¸ÑBÔBÐBÐBà�ð �9ÒÐØð å˜hÑ'Ô'×2Ò2Ð3EÑFÔFð õ " (¨OÑ<Ô<ð ð
	ØHÐHÐHÐHÐHÐHØ-Ð-¨eÑ4Ô4Ð4øÝð 	ð 	ð 	ØˆDð	øøøõ ˜8Ñ$Ô$ñ ,Õ-HÈÑ-RÔ-Rñ ,Ý9¸(ÈGÐTÑTÔTÐØ#×'Ò'¨Ñ.Ô.ˆØð 		åÐ$Ñ%Ô%¨Ò*Ð*Ý�tÐ$5×$<Ò$<Ñ$>Ô$>Ñ?Ô?Ñ@Ô@��ð #4×"9Ò"9Ñ";Ô";ð ð ‘J�C˜Ø �|�| s¨e | |Ø"'˜Ø˜ð (4ð ð 	&Ø$Ÿ[š[Ð)9Ñ:Ô:ˆNÝ˜.­#Ñ.Ô.ð &Ø%Ð%Ý*¨8Ñ4Ô4ð 	,å  Ñ*Ô*ð %Ý7¸¸xÐQXÐYÑYÔY�	Øð % ¨Q¢ Ý'¨¨x¸ÑCÔCÐCØ$Ð$Ý�KŠKð.ð �xÕ$<Ð!@Ð!@ñ	ô ð õ ,Ð+ð �;ÒÐØð Ý& xÑ0Ô0Ð4GÒGÐGå-¨e°XÐ5\ÐA\Ð^eÑfÔfˆØð 	ØˆJð "ÐØð .Ð!3Ð7OÐ!OÐ!OØð 	.Ý/°Ñ9Ô9ˆHØð .Ø%-Ð"ð ÐIÐIÐIð	ØCÐCÐCÐCÐCÐCØ+Ð+¨E¸7ÐCÑCÔCˆCØð Ø�
ðøåð 	ð 	ð 	ØˆDð	øøøð ˜VÒ#Ð#Ý*¨5Ñ1Ô1ˆØð 	ØˆJØ˜^Ò+Ð+õ 8¸ÈGÈMÐWYÐZÑZÔZˆ	Øð 	Øð @Ý# E¨8°YÑ?Ô?Ð?ØÐØð Ø>Ð>Ð>Ð>Ð>Ð>Ø'Ð'Ð(:¸EÑBÔBˆØð 	ØˆJõ $Ñ%Ô%€HØ�ÐÐØ˜Œ×"Ò"Ð#3Õ5MÑNÔNÐNð —+’+‘-”-€KÝ!'Ý×%Ò%Ñ'Ô'Ð-@Ð-@È$ð"ñ "ô "ð ð Ñˆ�vð ˜KÐ'Ð'ØˆMˆMˆMð (ð ð Õ% hÑ/Ô/ð Ý/°°xÈÐQÑQÔQˆ	Øð 	˜ Qš˜Ý  x°Ñ;Ô;Ð;ØÐõ $Ð#s5   §A  Á 
AÁAÃ,C= Ã=
D
Ä	D
Ê5K Ë
KËKré   c                 ó4   — | sdS t          | ¦  «        dz   dz  S )a  Rough token estimate (~4 chars/token) for pre-flight checks.

    Uses ceiling division so short texts (1-3 chars) never estimate as
    0 tokens, which would cause the compressor and pre-flight checks to
    systematically undercount when many short tool results are present.
    r   é   r´   rÉ  )ré   s    r   Úestimate_tokens_roughr÷  ‚  s&   € ð ð ØˆqÝ�‰IŒI˜‰M˜aÑÐr   Úmessagesc                 óD   — t          d„ | D ¦   «         ¦  «        }|dz   dz  S )z:Rough token estimate for a message list (pre-flight only).c              3   óN   K  — | ] }t          t          |¦  «        ¦  «        V — Œ!d S r›   ©rÌ   r”   ©r±   Úmsgs     r   r²   z1estimate_messages_tokens_rough.<locals>.<genexpr>�  s.   è è € Ð8Ð8¨•c�#˜c™(œ(‘m”mÐ8Ð8Ð8Ð8Ð8Ð8r   rö  r´   )Úsum)rø  Útotal_charss     r   Úestimate_messages_tokens_roughr   Ž  s-   € åÐ8Ð8¨xÐ8Ñ8Ô8Ñ8Ô8€KØ˜!‰O Ñ!Ð!r   )Úsystem_promptÚtoolsr  r  c                ó¼   — d}|r|t          |¦  «        z  }| r|t          d„ | D ¦   «         ¦  «        z  }|r|t          t          |¦  «        ¦  «        z  }|dz   dz  S )u<  Rough token estimate for a full chat-completions request.

    Includes the major payload buckets Hermes sends to providers:
    system prompt, conversation messages, and tool schemas.  With 50+
    tools enabled, schemas alone can add 20-30K tokens â€” a significant
    blind spot when only counting messages.
    r   c              3   óN   K  — | ] }t          t          |¦  «        ¦  «        V — Œ!d S r›   rû  rü  s     r   r²   z0estimate_request_tokens_rough.<locals>.<genexpr>¥  s.   è è € Ð=Ð=¨S�3�s 3™xœx™=œ=Ð=Ð=Ð=Ð=Ð=Ð=r   rö  r´   )rÌ   rþ  r”   )rø  r  r  rÿ  s       r   Úestimate_request_tokens_roughr  ”  sy   € ð €KØð *Ø•s˜=Ñ)Ô)Ñ)ˆØð >Ø•sÐ=Ð=°HÐ=Ñ=Ô=Ñ=Ô=Ñ=ˆØð 'Ø•s�3˜u™:œ:‘”Ñ&ˆØ˜!‰O Ñ!Ð!r   )r‹   )r÷   rø   )F)r‹   F)r‹   r‹   Nr‹   N)aÚ__doc__rÃ   rE  r   r‘  r?  Úpathlibr   Útypingr   r   r   r   Úurllib.parser   rA  rs  Úutilsr	   r
   rm  r   Ú	getLoggerÚ__name__rC  rœ   r”   r   Ú	frozensetrY   Ú__annotations__ÚcompileÚ
IGNORECASErc   ÚIPv4NetworkrÊ   rh   ri   rj   r®  r@  rk   rl   rU  r‹  rè  ÚMINIMUM_CONTEXT_LENGTHrë  r  r  rÀ   rÂ   r�   r–   r™   rž   r¢   r«   r­   rÓ   rî   ró   rÍ   r   Útupler  r  r  r0  r7  rJ  ri  rn  rv  r„  r†  rˆ  r�  r˜  r�  r¢  r³  r¶  r¹  r»  r¼  r½  r¾  rÂ  rÅ  rÓ  rÙ  rô   rô  r÷  r   r  r  r   r   ú<module>r     su  ððð ð ð Ð Ð Ð Ø €€€Ø 	€	€	€	Ø 	€	€	€	Ø €€€Ø Ð Ð Ð Ð Ð Ø ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ø !Ð !Ð !Ð !Ð !Ð !à €€€Ø €€€à :Ð :Ð :Ð :Ð :Ð :Ð :Ð :à 2Ð 2Ð 2Ð 2Ð 2Ð 2à	ˆÔ	˜8Ñ	$Ô	$€ð $¨¡*ð ð ð ð ð* &/ Yð 0ð 0ð 0ñ &ô &Ð �I˜c”Nð ð ñ ð, !�b”jØLØ„Mñô Ð ð )�9Ô(¨Ñ9Ô9Ð ð #ð ¨#ð ð ð ð ð& 46Ð �t˜C  c¨3 h¤Ð/Ô0Ð 5Ð 5Ñ 5Ø$%Ð ˜EÐ %Ð %Ñ %ØÐ ØGIÐ   S¨$¨s°D¸¸c¸´NÐ/BÔ*CÐ%CÔ DÐ IÐ IÑ IØ8:Ð # T¨#¨u¨*Ô%5Ð :Ð :Ñ :ØÐ ðð ð Ð ð /¨qÔ1Ð ð
  Ð ðað
 �wðað �wðað �wðað ˜ðað �wðað ˜ðað ˆfðað& ˆwð'að( �Fð)að* �Fð+að, ˆwð-að. �Fð/að0 ˆVð1að2 ˆwð3að4 ˆVð5að8 ˆgð9að< ˆvð=að að> ˆfð?að@ �6ðAaðB ˆvðCaðD ˆTðEaðT �yðUaðV ˜ðWaðX �YðYaðZ ˜ð[að\ �ð]að` ˆVðaaðf ˜ðgaðh �6ðiaðj ˆFðkaðp ˆvðqaðt 
ˆ6ðuaðB �fðCaðD �WðEað að aðF �TðGaðH �7ðIaðJ �ðKaðL ˆfðMaðN ˆfðOaðP ˆfðQaðR ˆFðSaðV ˆFðWaðZ �ð[að^ ˆvð_aðb �ðcaðf ˜fðgaðh ˜Fðiaðj   ðkaðl ˜Fðmaðn ˜Fðoaðp " 6ðqað aðr %Ø &ØØØØØØðAað að aÐ ðFÐ ðÐ ð <€ðÐ ð0 #ð 0¨#ð 0ð 0ð 0ð 0ð0ð 0˜3ð 0¨¨S°#¨X¬ð 0ð 0ð 0ð 0ð< cð <¨dð <ð <ð <ð <ðH #ð H¨$ð Hð Hð Hð Hð
$Ø�hð$à�8ð$ð ˜ð$ð �ð	$ð
 ˜ð$ð �}ð$ð Ð'ð$ð �Mð$ð �ið$ð �yð$ð �Gð$ð �9ð$ð ˜ið$ð " 9ð$ð �lð$ð  �\ð!$ð" (¨ð#$ð$ '-Ø"Ø&Ø!Ø#Ø ØØ (Ø"ØØ ð9$ð $ð $Ð �$�s˜C�x”.ð ð ñ ð@ sð ¨x¸¬}ð ð ð ð ð$:¨#ð :°$ð :ð :ð :ð :ð1 ð 1¨ð 1ð 1ð 1ð 1ðh:ð : sð :°Sð :À(È3Ä-ð :ð :ð :ð :ðz0˜cð 0ð 0ð 0ð 0ðð  #ð °ð ÀSð ÐZbÐcfÔZgð ð ð ð ð	  S¨# X¤ð 	°e¸CÀ¸H´oð 	È(ÐSVÌ-ð 	ð 	ð 	ð 	ð= T¨#¨s¨(¤^ð =¸À¼ð =ð =ð =ð =ð=¨D°°c°¬Nð =¸xÈ¼}ð =ð =ð =ð =ð˜d 3¨ 8œnð °°c¸3°h´ð ð ð ð ð.,˜d 3¨¨S°#¨X¬Ð#6Ô7ð ,À3ð ,ÈtÐTWÐY\ÐT\Ì~ð ,Ðbfð ,ð ,ð ,ð ,ð!+ð !+¨ð !+¸¸cÀ4ÈÈSÈÄ>Ð>QÔ9Rð !+ð !+ð !+ð !+ðL ØðOð OØðOàðOð ðOð 
ˆ#ˆt�C˜�HŒ~Ð
Ôð	Oð Oð Oð Oðd; ð ;ð ;ð ;ð ;ð˜T # s (œ^ð ð ð ð ðC˜sð C¨cð C¸3ð CÀ4ð Cð Cð Cð Cð* Sð °Cð ¸HÀS¼Mð ð ð ð ðW¨Sð W¸Cð WÀDð Wð Wð Wð Wð ¨ð °¸´ð ð ð ð ð¨cð °h¸s´mð ð ð ð ð8(¸ð (ÀÈÄð (ð (ð (ð (ðV Cð °sð ¸tð ð ð ð ð&4ð 4 ð 4¨sð 4¸Sð 4È(ÐSVÌ-ð 4ð 4ð 4ð 4ðn^ð ^ sð ^°cð ^ÀCð ^ÐQYÐZ]ÔQ^ð ^ð ^ð ^ð ^ðB# Cð #¨Cð #ð #ð #ð #ð¨3ð ¸#ð Èð ÐPXÐY\ÔP]ð ð ð ð ðP !Ø!ØØØØØØØð
1ð 
1Ð ˜t C¨ Hœ~ð 
ð 
ñ 
ð .0Ð ˜D  c œNÐ /Ð /Ñ /Ø),Ð  Ð ,Ð ,Ñ ,Ø!%Ð ð0°Sð 0¸TÀ#ÀsÀ(¼^ð 0ð 0ð 0ð 0ðh %'ðð ØðØ!ðàˆc„]ðð ð ð ðB¨ð °¸´ð ð ð ð ðF ØØ(,ØØ$(ðL$ð L$ØðL$àðL$ð ðL$ð  ™:ð	L$ð
 ðL$ð ˜T‘kðL$ð 	ðL$ð L$ð L$ð L$ð^	  ð 	 ¨ð 	 ð 	 ð 	 ð 	 ð"¨T°$°s¸C°x´.Ô-Að "Àcð "ð "ð "ð "ð Ø,0ð	"ð "ð "Ø�4˜˜S˜”>Ô"ð"ð ð"ð �D˜˜c 3˜hœÔ(Ô)ð	"ð
 	ð"ð "ð "ð "ð "ð "r   