+
    iHàjx#  ã                   ó  € R t ^ RIHt ^ RIHtHt R'tR R ltR R ltR R lt	R	 R
 lt
R R ltR(t]! R04      tR R ltR)R R lltR*tR R ltR R ltR R ltR R ltR R ltR R ltR R  ltR! R" ltR# R$ ltR% R& ltR# )+a  Endpoint-family detection for Anthropic-compatible base URLs.

A dozen services speak the Anthropic Messages API but differ in auth style, accepted beta
headers, and request quirks (MiniMax, Kimi/Moonshot, DeepSeek, OpenCode, Azure AI Foundry, Nous
Portal, Bedrock). Every such difference is decided from the configured base URL, so the
predicates live together here as pure functions (no I/O, SDK or credentials) that both
``agent/anthropic_adapter.py`` and ``agent/anthropic_message_convert.py`` can import without a
cycle.
)Úurlparse)Úbase_url_host_matchesÚbase_url_hostnamec                ó$   € V ^8„  d   QhR\         /# ©é   Úreturn©Ústr)Úformats   "Ú>/home/ubuntu/.hermes/hermes-agent/agent/anthropic_endpoints.pyÚ__annotate__r      s   € ÷ 5ñ 5¬#ñ 5ó    c                óH   € V '       d   \        V 4      P                  4       # R# )zMCoerce a base URL (str or ``httpx.URL``) to a stripped string; "" when falsy.Ú )r
   Ústrip©Úbase_urls   &r   Ú_normalize_base_url_textr      s   € ç$,Œ3ˆx‹=×ÑÓ Ð4°"Ð4r   c                ó$   € V ^8„  d   QhR\         /# r   r	   )r   s   "r   r   r      s   € ÷ Bñ B¤3ñ Br   c                óR   € \        V 4      P                  R4      P                  4       # )zY``_normalize_base_url_text`` + rstrip("/") + lower(), the shape most predicates match on.Ú/)r   ÚrstripÚlowerr   s   &r   Ú_normalized_lowerr      s!   € ä# HÓ-×4Ñ4°SÓ9×?Ñ?ÓAÐAr   c                ó>   € V ^8„  d   QhR\         R,          R\        /# ©r   r   Nr   ©r
   Úbool)r   s   "r   r   r      s"   € ÷ Bñ B´°tµð BÄñ Br   c                óH   € \        V 4      p\        V4      ;'       d    RV9  # )znAny non-anthropic.com endpoint (own x-api-key keys; skip OAuth detection). No base_url =
direct Anthropic API.zanthropic.com)r   r   ©r   Ú
normalizeds   & r   Ú"_is_third_party_anthropic_endpointr"      s&   € ô # 8Ó,€JÜ�
Ó×AÐA °zÑ AÐAr   c                ó>   € V ^8„  d   QhR\         R,          R\        /# r   r   )r   s   "r   r   r   #   s"   € ÷ Qñ Q¤s¨T¥zð Q´dñ Qr   c                ó6   € \        V 4      P                  R4      # )zAKimi's /coding endpoint, which requires a claude-code User-Agent.zhttps://api.kimi.com/coding)r   Ú
startswithr   s   &r   Ú_is_kimi_coding_endpointr&   #   s   € ä˜XÓ&×1Ñ1Ð2OÓPÐPr   c                ó>   € V ^8„  d   QhR\         R,          R\        /# r   r   )r   s   "r   r   r   (   s"   € ÷ @ñ @¤C¨$¥Jð @´4ñ @r   c                ó.   € \        T ;'       g    RR4      # )z&OpenCode's Zen/Go relay (opencode.ai).r   zopencode.ai©r   r   s   &r   Ú_is_opencode_endpointr*   (   s   € ä  § ¨R°Ó?Ð?r   Úk3c                ó>   € V ^8„  d   QhR\         R,          R\        /# ©r   ÚmodelNr   r   )r   s   "r   r   r   8   s"   € ÷ dñ d¤c¨D¥jð d´Tñ dr   c                 ó  € \        V \        4      '       g   R # V P                  4       P                  4       P	                  R^4      R,          p\        V4      ;'       d'    V\        9   ;'       g    VP                  \        4      # )Fr   éÿÿÿÿ)	Ú
isinstancer
   r   r   Úrsplitr   Ú_KIMI_FAMILY_EXACT_SLUGSr%   Ú_KIMI_FAMILY_MODEL_PREFIXES)r.   Úms   & r   Ú_model_name_is_kimi_familyr6   8   sb   € Ü�eœS×!Ò!ÙØ�‰‹×ÑÓ×$Ñ$ S¨!Ó,¨RÕ0€AÜ�‹7×cÐc˜Ô5Ñ5×bÐb¸¿¹ÔFaÓ9bÐcr   Nc                óX   € V ^8„  d   QhR\         R,          R\         R,          R\        /# )r   r   Nr.   r   r   )r   s   "r   r   r   ?   s*   € ÷ 	ñ 	¤s¨T¥zð 	¼#À½*ð 	ÔPTñ 	r   c                óÄ   a € \        S 4      ;'       gN    \        ;QJ d    V 3R lR 4       F  '       g   K   RM	  RM! V 3R lR 4       4      ;'       g    \        V4      # )un  Any Kimi / Moonshot Anthropic-Messages endpoint: the /coding endpoint, any api.kimi.com /
moonshot.ai / moonshot.cn host, or any endpoint (e.g. a private gateway) whose *model* is in
the Kimi family â€” the upstream enforces Kimi's thinking semantics regardless of hostname.
Decides whether unsigned reasoning_content-derived thinking blocks are preserved on replay.c              3   óP   <"  € T F  p\        S;'       g    R V4      x € K  	  R# 5i)r   Nr)   )Ú.0Údr   s   & €r   Ú	<genexpr>Ú+_is_kimi_family_endpoint.<locals>.<genexpr>F   s$   øé € ÐpÑAo¸AÔ$ X§^ ^°°Q×7Ð7ÓAoùs   ƒ&–&TF)zapi.kimi.comzmoonshot.aizmoonshot.cn)r&   Úanyr6   )r   r.   s   f&r   Ú_is_kimi_family_endpointr?   ?   sN   ø€ ô 	! Ó*÷ 	-ð 	-ß‹3ÔpÑAoÓp�3�3Š3ÔpÑAoÓpÓp÷	-ð 	-ä% eÓ,ðr   c                ó>   € V ^8„  d   QhR\         R,          R\        /# r-   r   )r   s   "r   r   r   R   s"   € ÷ 	Mñ 	M¬C°$­Jð 	M¼4ñ 	Mr   c                óì   € \        V \        4      '       g   R# V P                  4       P                  4       P	                  R^4      R,          p\        V4      ;'       d    VP                  \        4      # )zÅKnown DeepSeek thinking families behind an Anthropic-compatible relay.

Strip vendor namespaces, but do not treat arbitrary DeepSeek chat/distill
names as evidence of the thinking replay contract.
Fr   r0   )r1   r
   r   r   r2   r   r%   Ú!_DEEPSEEK_THINKING_MODEL_PREFIXES)r.   Únames   & r   Ú _model_name_is_deepseek_thinkingrD   R   sV   € ô �eœS×!Ò!ÙØ�;‰;‹=×ÑÓ ×'Ñ'¨¨QÓ/°Õ3€DÜ�‹:×LÐL˜$Ÿ/™/Ô*KÓLÐLr   c                ó>   € V ^8„  d   QhR\         R,          R\        /# r   r   )r   s   "r   r   r   ^   s"   € ÷ 
uñ 
u¬c°D­jð 
u¼Tñ 
ur   c                óZ   € \        T ;'       g    RR4      ;'       d    R\        V 4      9   # )ap  DeepSeek's ``/anthropic`` route. In thinking mode DeepSeek requires prior-turn ``thinking``
blocks to round-trip while the generic third-party path strips them; its blocks are unsigned,
so it gets the same strip-signed / keep-unsigned policy as Kimi. Pinned to the ``/anthropic``
path so the OpenAI-compatible base URL is not misclassified.

Per DeepSeek's published compatibility matrix the blocks are unsigned (no Anthropic-proprietary
signature, no ``redacted_thinking`` support), so this endpoint is handled with the same strip-signed /
keep-unsigned policy used for Kimi's ``/coding`` endpoint. See hermes-agent#16748.
r   zapi.deepseek.comú
/anthropic)r   r   r   s   &r   Ú_is_deepseek_anthropic_endpointrH   ^   s,   € ô ! § ¨RÐ1CÓD×tÐtÈÔYjÐksÓYtÑItÐtr   c                ó>   € V ^8„  d   QhR\         R,          R\        /# r   r   )r   s   "r   r   r   k   s"   € ÷ Vñ V¤s¨T¥zð V´dñ Vr   c                óþ   € \        T ;'       g    RR4      '       d   R#  ^ RIHp V! 4       pT'       d   \	        T4      MRp\        T4      ;'       d    \	        T ;'       g    R4      T8H  #   \         d     R# i ; i)a>  Nous Portal's Anthropic Messages route (Bearer JWT, verbatim catalog ids, native
thinking-signature replay). Trusted hosts only: prod ``inference-api.nousresearch.com`` or the
operator-set ``NOUS_INFERENCE_BASE_URL`` host (exact hostname equality, so neither lookalike
domains nor sibling hosts of the override match).r   zinference-api.nousresearch.comT)Ú_nous_inference_env_overrideF)r   Úhermes_cli.authrK   Ú	Exceptionr   r   )r   rK   ÚoverrideÚoverride_hosts   &   r   Ú_is_nous_portal_endpointrP   k   st   € ô
 ˜XŸ^˜^¨Ð-M×NÒNÙðÝ@Ù/Ó1ˆ÷ 4<Ô% hÔ/À€MÜ�Ó×UÐUÔ#4°X·^°^ÀÓ#DÈÑ#UÐUøô ô Úðús    A- Á-A<Á;A<c                ó>   € V ^8„  d   QhR\         R,          R\        /# r   r   )r   s   "r   r   r   {   s   € ÷ ñ ¤C¨$¥Jð ´4ñ r   c                óÒ   € \        V 4      p\        V 4      ;'       gK    VP                  \        4      ;'       g.    RV9   ;'       g!    \	        VR4      ;'       g    \	        VR4      # )a  Providers needing ``Authorization: Bearer`` instead of ``x-api-key``: MiniMax, Azure AI
Foundry, Palantir Foundry's LLM proxy, CommandCode, Nous Portal. Palantir/CommandCode use
hostname matching (not substring) so ``evil.com/palantirfoundry`` paths don't trigger it.ú	azure.comzpalantirfoundry.comzapi.commandcode.ai)r   rP   r%   Ú_MINIMAX_ANTHROPIC_PREFIXESr   r    s   & r   Ú_requires_bearer_authrU   {   s|   € ô # 8Ó,€Jä  Ó*÷ 	Cð 	CØ× Ñ Ô!<Ó=÷	Cð 	Cà˜*Ñ$÷	Cð 	Cô ! Ð-BÓC÷	Cð 	Cô ! Ð-AÓBðr   c                ó>   € V ^8„  d   QhR\         R,          R\        /# r   r   )r   s   "r   r   r   ‰   s"   € ÷ Eñ E¬c°D­jð E¼Tñ Er   c                ó:   € R\        V 4      P                  4       9   # )z;Endpoints that still gate 1M context behind a beta (Azure).rS   )r   r   r   s   &r   Ú_base_url_needs_context_1m_betarX   ‰   s   € àÔ2°8Ó<×BÑBÓDÑDÐDr   c                ó>   € V ^8„  d   QhR\         R,          R\        /# r   r   )r   s   "r   r   r   Ž   s"   € ÷ Oñ O¬S°4­Zð O¼Dñ Or   c                ó>   € \        V 4      P                  \        4      # )z¡MiniMax's Anthropic-compatible endpoints, which reject the fine-grained-tool-streaming and
context-1m betas (stripped even though MiniMax also uses Bearer auth).)r   r%   rT   r   s   &r   Ú_is_minimax_anthropic_endpointr[   Ž   s   € ô ˜XÓ&×1Ñ1Ô2MÓNÐNr   c                ó>   € V ^8„  d   QhR\         R,          R\        /# r   r   )r   s   "r   r   r   ”   s"   € ÷ Iñ I¬3°­:ð I¼$ñ Ir   c                ó6  € \        V 4      pV'       g   R# \        V4      pRVP                  ;'       g    RP                  4       P	                  R4       R2pRV9   ;'       g    RV9   pT;'       d(    RVP
                  ;'       g    RP                  4       9   # )a  Azure-hosted Anthropic Messages endpoints serving ``/anthropic``: modern Foundry
(``*.services.ai.azure.*``) and legacy Azure OpenAI (``*.openai.azure.*``) hosts; opts them
into ``api-version`` query plumbing. Deliberately no finite TLD allow-list, so
sovereign/private clouds work.FÚ.r   z.services.ai.azure.z.openai.azure.rG   )r   r   Úhostnamer   r   Úpath)r   r!   ÚparsedÚhost_paddedÚis_azure_hosts   &    r   Ú_is_azure_anthropic_endpointrd   ”   sŽ   € ô
 *¨(Ó3€JßÙÜ�jÓ!€FØ�v—‘×,Ð,¨"×3Ñ3Ó5×<Ñ<¸SÓAÐBÀ!ÐD€KØ)¨[Ñ8×[Ð[Ð<LÐP[Ñ<[€MØ×HÐH˜\¨f¯k©k×.?Ð.?¸R×-FÑ-FÓ-HÑHÐHr   c                ó>   € V ^8„  d   QhR\         R,          R\        /# r   r   )r   s   "r   r   r   ¢   s   € ÷ ñ ¬3°­:ð ¼$ñ r   c                ó   € \        T ;'       g    R4      p\        ;QJ d+    R VP                  R4       4       F  '       g   K   RM 	  RM! R VP                  R4       4       4      ;'       d!    \        VR4      ;'       g    \        VR4      # )zÂAmazon Bedrock's runtime host (``bedrock-runtime[-fips].<region>.amazonaws.com[.cn]``, and VPC
endpoint names carrying the same label), which the AnthropicBedrock SDK path binds as its base URL.r   c              3   óB   "  € T F  qP                  R 4      x € K  	  R# 5i)zbedrock-runtimeN)r%   )r:   Úlabels   & r   r<   Ú/_is_bedrock_runtime_endpoint.<locals>.<genexpr>¦   s   é € ÐPÁ°u×ÑÐ 1×2Ð2Ãùs   ‚r^   TFzamazonaws.comzamazonaws.com.cn)r   r>   Úsplitr   ©r   Úhosts   & r   Ú_is_bedrock_runtime_endpointrm   ¢   sl   € ô ˜XŸ^˜^¨Ó,€Dß‹3ÑPÀÇ
Á
È3ÄÓP�3�3Š3ÑPÀÇ
Á
È3ÄÓPÓP÷ ð Ü˜d OÓ4×gÐgÔ8MÈdÐTfÓ8gðr   c                ó>   € V ^8„  d   QhR\         R,          R\        /# r   r   )r   s   "r   r   r   «   s"   € ÷ ^ñ ^¤S¨4¥Zð ^´Dñ ^r   c                óh   € \        T ;'       g    R4      pVR8H  ;'       g    VP                  R4      # )zjVertex AI hosts: global ``aiplatform.googleapis.com`` and regional ``<region>-aiplatform.googleapis.com``.r   zaiplatform.googleapis.comz-aiplatform.googleapis.com)r   Úendswithrk   s   & r   Ú_is_vertex_ai_endpointrq   «   s0   € ä˜XŸ^˜^¨Ó,€DØÐ.Ñ.×]Ð]°$·-±-Ð@\Ó2]Ð]r   c                ó>   € V ^8„  d   QhR\         R,          R\        /# r   r   )r   s   "r   r   r   ±   s   € ÷ ñ ¬3°­:ð ¼$ñ r   c                ód   € \        V 4      ;'       g    \        V 4      ;'       g    \        V 4      # )a  Cloud platforms serving Claude under Anthropic's own thinking signatures: Bedrock, Vertex AI and
Azure AI Foundry ``/anthropic``. Anthropic documents ``signature`` values as compatible across the
Claude API, Bedrock and Google Cloud, so these replay signed thinking like the direct API.)rm   rq   rd   r   s   &r   Ú_is_claude_platform_endpointrt   ±   s5   € ô
 	% XÓ.÷ 	2ð 	2Ü! (Ó+÷	2ð 	2ä'¨Ó1ðr   )z https://api.minimax.io/anthropicz"https://api.minimaxi.com/anthropic)zkimi-Úkimi_z	moonshot-Ú	moonshot_zk1.zk1-zk2.zk2-Úk25zk2.5zk3.zk3-)N)z
deepseek-rzdeepseek-v4Údeepseek_v4zdeepseek-proÚdeepseek_prozdeepseek-flashÚdeepseek_flash)Ú__doc__Úurllib.parser   Úutilsr   r   rT   r   r   r"   r&   r*   r4   Ú	frozensetr3   r6   r?   rB   rD   rH   rP   rU   rX   r[   rd   rm   rq   rt   © r   r   Ú<module>r€      s˜   ðñõ "ç :àhÐ õ5õ
Bõ
BõQõ
@ðÐ ñ
 % d VÓ,Ð õd÷	ð%Ð !õ	Mõ
uõVõ õEõ
OõIõõ^÷r   