
    i1A                       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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mZ daeed<   d	 Z ej        e          Zd
ddddZdddddddZdZdZdZddddddd
dddddddddZdZ de!de"fdZ#dee"         fd Z$	 dde!d!ee"         de"fd"Z%de!de&fd#Z'de!de&fd$Z(de!de&fd%Z)g d&Z*d'Z+d(Z,d)Z-d*d+gZ.d,Z/da0ee!         ed-<   de!fd.Z1d/Z2d0Z3de!fd1Z4d2e!de&fd3Z5de!fd4Z6d5e!dz  de&fd6Z7d5e!dz  de&fd7Z8d8Z9de!dz  de&fd9Z:dd5e!dz  de!dz  de&fd:Z;d5e!dz  de&fd;Z<d5e!dz  de&fd<Z=d=d>d5e!dz  d?e&de>e!         fd@Z?	 	 dd=d>dAe!d5e!dBe@d?e&fdCZAdDe!fdEZBdeee!ef                  fdFZCdeee!ef                  fdGZDdee!         fdHZEdIee!ef         de&fdJZFd=dKdLe!dMe&dee!ef         fdNZGdIee!ef         dee!         fdOZHddPdQe!dLe!dRe"dSee>         ddf
dTZIddIeee!ef                  dee!         fdUZJdVe!dIeee!ef                  dee!         fdWZKdee!         fdXZLdee!         fdYZMdZZNd[ZOd\ZPd]ZQ e
            d^z  ZRdeSfd_ZTdeee!ef                  fd`ZUdeee!ef                  fdaZVde!de&fdbZWdde!dce&de!fddZXdee!de!fdfZYdgedee!ef         fdhZZdiee         dee         fdjZ[dke!dee!e!f         fdlZ\dmedeee!ef                  fdnZ]dddodpedqe"dree^         defdsZ_dtee!ef         deee!ef                  fduZ`dvedefdwZa	 	 ddxee         d5e!dz  de!dz  deee         ee         f         fdyZb	 	 	 	 	 	 	 dde!dxee         dieee                  dzee"         d{eee!ef                  d|ee!         d}e&dce&d!ee"         d5e!dz  d~e&d?e&dee!ef         fdZcdS )u  Anthropic Messages API adapter for Hermes Agent.

Translates between Hermes's internal OpenAI-style message format and
Anthropic's Messages API. Follows the same pattern as the codex_responses
adapter — all provider-specific logic is isolated here.

Auth supports:
  - Regular API keys (sk-ant-api*) → x-api-key header
  - OAuth setup-tokens (sk-ant-oat*) → Bearer auth + beta header
  - Claude Code credentials (~/.claude.json or ~/.claude/.credentials.json) → Bearer auth
    N)Path)get_hermes_home)AnyDictListOptionalTuple)base_url_host_matchesnormalize_proxy_env_vars._anthropic_sdkc                  V    t           du r	 ddl} | a n# t          $ r da Y nw xY wt           S )zMReturn the ``anthropic`` SDK module, importing lazily. None if not installed..r   N)r   	anthropicImportError)_sdks    </home/ubuntu/.hermes/hermes-agent/agent/anthropic_adapter.py_get_anthropic_sdkr   "   sQ     	"$$$$!NN 	" 	" 	"!NNN	"s    !!i }  i>  @  i  )xhighhighmediumlowmaxr   r   r   r   )r   r   r   r   r   minimal)4-74.7)z4-6z4.6r   r   i  i   i       i   )zclaude-opus-4-7zclaude-opus-4-6zclaude-sonnet-4-6zclaude-opus-4-5zclaude-sonnet-4-5zclaude-haiku-4-5zclaude-opus-4zclaude-sonnet-4zclaude-3-7-sonnetzclaude-3-5-sonnetzclaude-3-5-haikuzclaude-3-opuszclaude-3-sonnetzclaude-3-haikuminimaxmodelreturnc                     |                                                      dd          }d}t          }t                                          D ]-\  }}||v r$t          |          t          |          k    r|}|}.|S )a  Look up the max output token limit for an Anthropic model.

    Uses substring matching against _ANTHROPIC_OUTPUT_LIMITS so date-stamped
    model IDs (claude-sonnet-4-5-20250929) and variant suffixes (:1m, :fast)
    resolve correctly.  Longest-prefix match wins to avoid e.g. "claude-3-5"
    matching before "claude-3-5-sonnet".

    Normalizes dots to hyphens so that model names like
    ``anthropic/claude-opus-4.6`` match the ``claude-opus-4-6`` table key.
    .- )lowerreplace_ANTHROPIC_DEFAULT_OUTPUT_LIMIT_ANTHROPIC_OUTPUT_LIMITSitemslen)r   mbest_keybest_valkeyvals         r   _get_anthropic_max_outputr/   s   sy     	c3''AH.H,2244  S!88C3x==00HHO    c                     t          | t                    rdS t          | t          t          f          sdS 	 ddl}|                    |           sdS n# t          $ r Y dS w xY wt          |           }|dk    r|ndS )a  Return ``value`` floored to a positive int, or ``None`` if it is not a
    finite positive number. Ported from openclaw/openclaw#66664.

    Anthropic's Messages API rejects ``max_tokens`` values that are 0,
    negative, non-integer, or non-finite with HTTP 400. Python's ``or``
    idiom (``max_tokens or fallback``) correctly catches ``0`` but lets
    negative ints and fractional floats (``-1``, ``0.5``) through to the
    API, producing a user-visible failure instead of a local error.
    Nr   )
isinstanceboolintfloatmathisfinite	Exception)valuer6   flooreds      r   &_resolve_positive_anthropic_max_tokensr;      s     % tec5\** t}}U## 	4	   tt%jjGkk77t+s   A 
A! A!context_lengthc                     t          |           }||S t          |          }|dk    r|S t          d|d| d          )u  Resolve the ``max_tokens`` budget for an Anthropic Messages call.

    Prefers ``requested`` when it is a positive finite number; otherwise
    falls back to the model's output ceiling. Raises ``ValueError`` if no
    positive budget can be resolved (should not happen with current model
    table defaults, but guards against a future regression where
    ``_get_anthropic_max_output`` could return ``0``).

    Separately, callers apply a context-window clamp — this resolver does
    not, to keep the positive-value contract independent of endpoint
    specifics.

    Ported from openclaw/openclaw#66664 (resolveAnthropicMessagesMaxTokens).
    Nr   zJAnthropic Messages adapter requires a positive max_tokens value for model z; got z and no model default resolved.)r;   r/   
ValueError)	requestedr   r<   resolvedfallbacks        r   &_resolve_anthropic_messages_max_tokensrB      ss    & 6i@@H(//H!||
	M	M 	M )	M 	M 	M  r0   c                 D     t           fdt          D                       S )zBReturn True for Claude 4.6+ models that support adaptive thinking.c              3       K   | ]}|v V  	d S N .0vr   s     r   	<genexpr>z._supports_adaptive_thinking.<locals>.<genexpr>   s'      AAaqEzAAAAAAr0   )any_ADAPTIVE_THINKING_SUBSTRINGSr   s   `r   _supports_adaptive_thinkingrN      s'    AAAA#@AAAAAAr0   c                 D     t           fdt          D                       S )uJ  Return True for models that accept the 'xhigh' adaptive effort level.

    Opus 4.7 introduced xhigh as a distinct level between high and max.
    Pre-4.7 adaptive models (Opus/Sonnet 4.6) only accept low/medium/high/max
    and reject xhigh with an HTTP 400. Callers should downgrade xhigh→max
    when this returns False.
    c              3       K   | ]}|v V  	d S rE   rF   rG   s     r   rJ   z)_supports_xhigh_effort.<locals>.<genexpr>   s'      <<aqEz<<<<<<r0   )rK   _XHIGH_EFFORT_SUBSTRINGSrM   s   `r   _supports_xhigh_effortrR      s)     <<<<#;<<<<<<r0   c                 D     t           fdt          D                       S )a9  Return True for models that 400 on any non-default temperature/top_p/top_k.

    Opus 4.7 explicitly rejects sampling parameters; later Claude releases are
    expected to follow suit.  Callers should omit these fields entirely rather
    than passing zero/default values (the API rejects anything non-null).
    c              3       K   | ]}|v V  	d S rE   rF   rG   s     r   rJ   z+_forbids_sampling_params.<locals>.<genexpr>   s'      BBaqEzBBBBBBr0   )rK   _NO_SAMPLING_PARAMS_SUBSTRINGSrM   s   `r   _forbids_sampling_paramsrV      s)     BBBB#ABBBBBBr0   )zinterleaved-thinking-2025-05-14&fine-grained-tool-streaming-2025-05-14context-1m-2025-08-07rW   rX   zfast-mode-2026-02-01zclaude-code-20250219zoauth-2025-04-20z2.1.74_claude_code_version_cachec                  d   ddl } dD ]}	 |                     |dgddd          }|j        dk    rj|j                                        rQ|j                                                                        d         }|r|d                                         r|c S # t          $ r Y w xY wt          S )a2  Detect the installed Claude Code version, fall back to a static constant.

    Anthropic's OAuth infrastructure validates the user-agent version and may
    reject requests with a version that's too old.  Detecting dynamically means
    users who keep Claude Code updated never hit stale-version 400s.
    r   N)claudeclaude-codez	--versionT   capture_outputtexttimeout)	
subprocessrun
returncodestdoutstripsplitisdigitr8   _CLAUDE_CODE_VERSION_FALLBACK)_spcmdresultversions       r   _detect_claude_code_versionrn     s     (  	WWk"#$   F  A%%&-*=*=*?*?% ---//5577: #wqz1133 #"NNN 	 	 	D	((s   BB
B('B(z9You are Claude Code, Anthropic's official CLI for Claude.mcp_c                  :    t           t                      a t           S )zKLazily detect the installed Claude Code version when OAuth headers need it.)rY   rn   rF   r0   r   _get_claude_code_versionrq   )  s     ")%@%B%B"%%r0   r-   c                     | sdS |                      d          rdS |                      d          rdS |                      d          rdS |                      d          rdS dS )u  Check if the key is an Anthropic OAuth/setup token.

    Positively identifies Anthropic OAuth tokens by their key format:
    - ``sk-ant-`` prefix (but NOT ``sk-ant-api``) → setup tokens, managed keys
    - ``eyJ`` prefix → JWTs from the Anthropic OAuth flow
    - ``cc-`` prefix → Claude Code OAuth access tokens (from CLAUDE_CODE_OAUTH_TOKEN)

    Non-Anthropic keys (MiniMax, Alibaba, etc.) don't match any pattern
    and correctly return False.
    Fz
sk-ant-apizsk-ant-TeyJzcc-
startswith)r-   s    r   _is_oauth_tokenrv   1  sz      u
~~l## u
~~i   t
~~e t
~~e t5r0   c                 L    | sdS t          |                                           S )zNormalize SDK/base transport URL values to a plain string for inspection.

    Some client objects expose ``base_url`` as an ``httpx.URL`` instead of a raw
    string.  Provider/auth detection should accept either shape.
    r#   )strrf   )base_urls    r   _normalize_base_url_textrz   M  s)      rx==   r0   ry   c                     t          |           }|sdS |                    d                                          }d|v rdS dS )a#  Return True for non-Anthropic endpoints using the Anthropic Messages API.

    Third-party proxies (Azure AI Foundry, AWS Bedrock, self-hosted) authenticate
    with their own API keys via x-api-key, not Anthropic OAuth tokens. OAuth
    detection should be skipped for these endpoints.
    F/zanthropic.comT)rz   rstripr$   ry   
normalizeds     r   "_is_third_party_anthropic_endpointr   X  sR     *(33J u""3''--//J*$$u4r0   c                     t          |           }|sdS |                    d                                                              d          S )zEReturn True for Kimi's /coding endpoint that requires claude-code UA.Fr|   zhttps://api.kimi.com/codingrz   r}   r$   ru   r~   s     r   _is_kimi_coding_endpointr   h  sK    )(33J uS!!''))445RSSSr0   )
zkimi-kimi_z	moonshot-	moonshot_zk1.zk1-zk2.zk2-k25zk2.5c                     t          | t                    sdS |                                                                 }|sdS d|v r|                    dd          d         }|                    t                    S )NFr|      )r2   rx   rf   r$   rsplitru   _KIMI_FAMILY_MODEL_PREFIXES)r   r*   s     r   _model_name_is_kimi_familyr     ss    eS!! uA u
axxHHS!R <<3444r0   c                 ~    t          |           rdS dD ]}t          | pd|          r dS t          |          rdS dS )uz  Return True for any Kimi / Moonshot Anthropic-Messages-speaking endpoint.

    Broader than ``_is_kimi_coding_endpoint`` — matches:

    - Kimi's official ``/coding`` URL (legacy check, preserved)
    - Any ``api.kimi.com`` / ``moonshot.ai`` / ``moonshot.cn`` host
    - Custom or proxied endpoints whose *model* name is in the Kimi / Moonshot
      family (``kimi-*``, ``moonshot-*``, ``k1.*``, ``k2.*``, …).  Users with
      ``api_mode: anthropic_messages`` on a private gateway fronting Kimi
      fall into this branch — the upstream still enforces Kimi's thinking
      semantics (reasoning_content required on every replayed tool-call
      message) regardless of the gateway's hostname.

    Used to decide whether to drop Anthropic's ``thinking`` kwarg and to
    preserve unsigned reasoning_content-derived thinking blocks on replay.
    See hermes-agent#13848, #17057.
    T)zapi.kimi.comzmoonshot.aizmoonshot.cnr#   F)r   r
   r   )ry   r   _domains      r   _is_kimi_family_endpointr     sd    $  )) tA   R99 	44	!%(( t5r0   c                     t          | pdd          sdS t          |           }|sdS d|                    d                                          v S )u  Return True for DeepSeek's Anthropic-compatible endpoint.

    DeepSeek's ``/anthropic`` route speaks the Anthropic Messages protocol
    but, when thinking mode is enabled, requires the ``thinking`` blocks
    from prior assistant turns to round-trip on subsequent requests — the
    generic third-party path strips them and triggers HTTP 400::

        The content[].thinking in the thinking mode must be passed back
        to the API.

    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.  The match is pinned to
    the ``/anthropic`` path so the OpenAI-compatible ``api.deepseek.com``
    base URL (which never reaches this adapter) is not misclassified.
    See hermes-agent#16748.
    r#   zapi.deepseek.comFz
/anthropicr|   )r
   rz   r}   r$   r~   s     r   _is_deepseek_anthropic_endpointr     s_    & !R1CDD u)(33J u:,,S11779999r0   c                     t          |           }|sdS |                    d                                          }|                    d          S )a@  Return True for Anthropic-compatible providers that require Bearer auth.

    Some third-party /anthropic endpoints implement Anthropic's Messages API but
    require Authorization: Bearer *** of Anthropic's native x-api-key header.
    MiniMax's global and China Anthropic-compatible endpoints follow this pattern.
    Fr|   )z https://api.minimax.io/anthropicz"https://api.minimaxi.com/anthropicr   r~   s     r   _requires_bearer_authr     sR     *(33J u""3''--//J  !klllr0   Fdrop_context_1m_betar   c                    t          |           r!t          t          hfdt          D             S |rd t          D             S t          S )u  Return the beta headers that are safe for the configured endpoint.

    MiniMax's Anthropic-compatible endpoints (Bearer-auth) reject requests
    that include Anthropic's ``fine-grained-tool-streaming`` beta — every
    tool-use message triggers a connection error.  Strip that beta for
    Bearer-auth endpoints while keeping all other betas intact.

    The ``context-1m-2025-08-07`` beta is also stripped for Bearer-auth
    endpoints — MiniMax hosts its own models, not Claude, so the header is
    irrelevant at best and risks request rejection at worst.

    ``drop_context_1m_beta=True`` additionally strips the 1M-context beta on
    otherwise-unrelated endpoints. The OAuth retry path flips this flag after
    a subscription rejects the beta with
    "The long context beta is not yet available for this subscription" so
    subsequent requests in the same session don't repeat the probe. See the
    reactive recovery loop in ``run_agent.py`` and issue-comment history on
    PR #17680 for the full rationale.
    c                     g | ]}|v|	S rF   rF   )rH   b	_strippeds     r   
<listcomp>z._common_betas_for_base_url.<locals>.<listcomp>  s#    ???aAY,>,>,>,>,>r0   c                 (    g | ]}|t           k    |S rF   )_CONTEXT_1M_BETArH   r   s     r   r   z._common_betas_for_base_url.<locals>.<listcomp>  s#    BBBaA1A,A,A,A,A,Ar0   )r   _TOOL_STREAMING_BETAr   _COMMON_BETAS)ry   r   r   s     @r   _common_betas_for_base_urlr     s^    0 X&& @)+;<	????=???? CBB=BBBBr0   api_keyra   c                   t                      }|t          d          t                       ddlm} t          |          }t          |t          t          f          r|dk    r|nd}d |t          |          d          i}|rAd	|	                                v }	|	r$d
|vr |
                    d          |d<   d
di|d<   n||d<   t          ||          }
t          |          r(| |d<   ddi|
rdd                    |
          ini |d<   nt          |          r"| |d<   |
rdd                    |
          i|d<   nt          |          r"| |d<   |
rdd                    |
          i|d<   nlt!          |           r<|
t"          z   }| |d<   d                    |          dt%                       ddd|d<   n!| |d<   |
rdd                    |
          i|d<    |j        di |S )a  Create an Anthropic client, auto-detecting setup-tokens vs API keys.

    If *timeout* is provided it overrides the default 900s read timeout.  The
    connect timeout stays at 10s.  Callers pass this from the per-provider /
    per-model ``request_timeout_seconds`` config so Anthropic-native and
    Anthropic-compatible providers respect the same knob as OpenAI-wire
    providers.

    ``drop_context_1m_beta=True`` strips ``context-1m-2025-08-07`` from the
    client-level ``anthropic-beta`` header. Used by the reactive OAuth retry
    path in ``run_agent.py`` when a subscription rejects the beta; leave at
    its default on fresh clients so 1M-capable subscriptions keep the
    capability.

    Returns an anthropic.Anthropic instance.
    NzpThe 'anthropic' package is required for the Anthropic provider. Install it with: pip install 'anthropic>=0.39.0'r   Timeout      @ra         $@ra   connectz	azure.comzapi-versionr|   ry   z
2025-04-15default_queryr   r   
User-Agentzclaude-code/0.1.0anthropic-beta,default_headers
auth_tokenclaude-cli/ (external, cli)cli)r   z
user-agentzx-apprF   )r   r   r   httpxr   rz   r2   r4   r5   r$   r}   r   r   joinr   r   rv   _OAUTH_ONLY_BETASrq   	Anthropic)r   ry   ra   r   r   r   normalized_base_url_read_timeoutkwargs_is_azure_endpointcommon_betas	all_betass               r   build_anthropic_clientr     s   . ())N?
 
 	

 28<< *7S%L A A]gPQkkGGX]M775#7#7FFFF  
5
 ),?,E,E,G,GG 	5-7J"J"J!4!;!;C!@!@F:'4l&CF?##!4F:-1  L
  )) *S $y-%
>JR!388L#9#9::PR%
 !! 
2	3	3 !S  '| 	S)9388L;Q;Q(RF$%	+H	5	5 S
 $y 	S)9388L;Q;Q(RF$%		!	! S !#44	&|!hhy11T(@(B(BTTT%
 %
 !! $y 	S)9388L;Q;Q(RF$%#>#--f---r0   regionc                    t                      }|t          d          t          |d          st          d          ddlm} |                    |  |dd	          d
d                    t                    i          S )u  Create an AnthropicBedrock client for Bedrock Claude models.

    Uses the Anthropic SDK's native Bedrock adapter, which provides full
    Claude feature parity: prompt caching, thinking budgets, adaptive
    thinking, fast mode — features not available via the Converse API.

    Attaches the common Anthropic beta headers as client-level defaults so
    that Bedrock-hosted Claude models get the same enhanced features as
    native Anthropic. The ``context-1m-2025-08-07`` beta in particular
    unlocks the 1M context window for Opus 4.6/4.7 on Bedrock — without
    it, Bedrock caps these models at 200K even though the Anthropic API
    serves them with 1M natively.

    Auth uses the boto3 default credential chain (IAM roles, SSO, env vars).
    NznThe 'anthropic' package is required for the Bedrock provider. Install it with: pip install 'anthropic>=0.39.0'AnthropicBedrockzWanthropic.AnthropicBedrock not available. Upgrade with: pip install 'anthropic>=0.39.0'r   r   r   r   r   r   r   )
aws_regionra   r   )r   r   hasattrr   r   r   r   r   )r   r   r   s      r   build_anthropic_bedrock_clientr   V  s      ())N?
 
 	
 >#566 
<
 
 	
 **t444)388M+B+BC +   r0   c                     t          j                    dk    rdS 	 t          j        g dddd          } n7# t          t          j        f$ r t                              d           Y dS w xY w| j        dk    rt                              d	           dS | j	        
                                }|sdS 	 t          j        |          }n0# t          j        $ r t                              d
           Y dS w xY w|                    d          }|r\t          |t                     rG|                    dd          }|r/||                    dd          |                    dd          ddS dS )a  Read Claude Code OAuth credentials from the macOS Keychain.

    Claude Code >=2.1.114 stores credentials in the macOS Keychain under the
    service name "Claude Code-credentials" rather than (or in addition to)
    the JSON file at ~/.claude/.credentials.json.

    The password field contains a JSON string with the same claudeAiOauth
    structure as the JSON file.

    Returns dict with {accessToken, refreshToken?, expiresAt?} or None.
    DarwinN)securityzfind-generic-passwordz-szClaude Code-credentialsz-wTr]   r^   z5Keychain: security command not available or timed outr   z6Keychain: no entry found for 'Claude Code-credentials'z/Keychain: credentials payload is not valid JSONclaudeAiOauthaccessTokenr#   refreshToken	expiresAtmacos_keychainr   r   r   source)platformsystemrb   rc   OSErrorTimeoutExpiredloggerdebugrd   re   rf   jsonloadsJSONDecodeErrorgetr2   dict)rl   rawdata
oauth_dataaccess_tokens        r   +_read_claude_code_credentials_from_keychainr   z  s    H$$t    
 
 
 Z./   LMMMtt AMNNNt
-



C tz#   FGGGtt /**J jT22 !~~mR88 	+ *~r B B'^^K;;*	   4s!   6 0A*)A*2C )C43C4c                  F   t                      } | r| S t          j                    dz  dz  }|                                r	 t	          j        |                    d                    }|                    d          }|r\t          |t                    rG|                    dd          }|r/||                    dd          |                    d	d
          ddS nD# t          j
        t          t          f$ r%}t                              d|           Y d}~nd}~ww xY wdS )u4  Read refreshable Claude Code OAuth credentials.

    Checks two sources in order:
      1. macOS Keychain (Darwin only) — "Claude Code-credentials" entry
      2. ~/.claude/.credentials.json file

    This intentionally excludes ~/.claude.json primaryApiKey. Opencode's
    subscription flow is OAuth/setup-token based with refreshable credentials,
    and native direct Anthropic provider usage should follow that path rather
    than auto-detecting Claude's first-party managed key.

    Returns dict with {accessToken, refreshToken?, expiresAt?} or None.
    .claude.credentials.jsonutf-8encodingr   r   r#   r   r   r   claude_code_credentials_filer   z.Failed to read ~/.claude/.credentials.json: %sN)r   r   homeexistsr   r   	read_textr   r2   r   r   r   IOErrorr   r   )kc_creds	cred_pathr   r   r   es         r   read_claude_code_credentialsr     sF    ;<<H  	i'*==I N	N:i1171CCDDD/22J jT:: )~~mR@@ '3(2~r(J(J%/^^K%C%C"@	   $gw7 	N 	N 	NLLI1MMMMMMMM	N 4s   BC D9DDc                     t          j                    dz  } |                                 r	 t          j        |                     d                    }|                    dd          }t          |t                    r(|	                                r|	                                S nD# t          j
        t          t          f$ r%}t                              d|           Y d}~nd}~ww xY wdS )zJRead Claude's native managed key from ~/.claude.json for diagnostics only.z.claude.jsonr   r   primaryApiKeyr#   z!Failed to read ~/.claude.json: %sN)r   r   r   r   r   r   r   r2   rx   rf   r   r   r   r   r   )claude_jsonr   primary_keyr   s       r   read_claude_managed_keyr     s    )++.K A	A:k33W3EEFFD((?B77K+s++ +0A0A0C0C +"((***$gw7 	A 	A 	ALL<a@@@@@@@@	A4s   A:B( (C)C$$C)credsc                     ddl }|                     dd          }|s"t          |                     d                    S t          |                                 dz            }||dz
  k     S )zACheck if Claude Code credentials have a non-expired access token.r   Nr   r     i`  )timer   r3   r4   )r   r   
expires_atnow_mss       r   is_claude_code_token_validr     sl    KKK;**J .EIIm,,--- t#$$FZ&())r0   use_jsonrefresh_tokenr   c          	         ddl }ddl}ddl}| st          d          d}|r-t	          j        d| |d                                          }d}n2|j                            d| |d                                          }d}d	d
g}d}|D ]X}	|j	        
                    |	||dt                       ddd          }
	 |j	                            |
d          5 }t	          j        |                                                                          }ddd           n# 1 swxY w Y   n5# t           $ r(}|}t"                              d|	|           Y d}~d}~ww xY w|                    dd          }|st          d          |                    d|           }|                    dd          }||t)          |                                 dz            |dz  z   dc S ||t          d          )zIRefresh an Anthropic OAuth token without mutating local credential files.r   Nzrefresh_token is required$9d1c250a-e61b-44d9-88ed-5944d1962f5er   )
grant_typer   	client_idapplication/jsonz!application/x-www-form-urlencodedz*https://platform.claude.com/v1/oauth/token,https://console.anthropic.com/v1/oauth/tokenr   r   zContent-Typer   POSTr   headersmethod
   ra   z(Anthropic token refresh failed at %s: %sr   r#   z3Anthropic refresh response was missing access_token
expires_in  r   r   r   expires_at_mszAnthropic token refresh failed)r   urllib.parseurllib.requestr>   r   dumpsencodeparse	urlencoderequestRequestrq   urlopenr   readdecoder8   r   r   r   r4   )r   r   r   urllibr   r   content_typetoken_endpoints
last_errorendpointreqresprl   excr   next_refreshr  s                    r   refresh_anthropic_oauth_purer     s   KKK 645556I ;z)*"
 
   688	 	
 *|%%)*"'
 '
   688	 	
 ; 	56O J# 
 
n$$ ,X,D,F,FXXX   % 
 
	''R'88 :DDIIKK$6$6$8$899: : : : : : : : : : : : : : : 	 	 	JLLCXsSSSHHHH	
 zz."55 	TRSSSzz/=AAZZd33
() t!344
T8IJ
 
 	
 	
 	
 
5
6
66s<   >D+9DD+D#	#D+&D#	'D++
E5EEc                 ~   |                      dd          }|st                              d           dS 	 t          |d          }t	          |d         |d         |d	                    t                              d
           |d         S # t
          $ r&}t                              d|           Y d}~dS d}~ww xY w)z6Attempt to refresh an expired Claude Code OAuth token.r   r#   u-   No refresh token available — cannot refreshNFr   r   r   r  z.Successfully refreshed Claude Code OAuth tokenz'Failed to refresh Claude Code token: %s)r   r   r   r   _write_claude_code_credentialsr8   )r   r   	refreshedr   s       r   _refresh_oauth_tokenr$  8  s    IInb11M DEEEt0OOO	&n%o&o&	
 	
 	

 	EFFF((   >BBBttttts   AB 
B<B77B<)scopesr   r  r%  c                   t          j                    dz  dz  }	 i }|                                r(t          j        |                    d                    }| ||d}|||d<   nd|v rd|d         v r|d         d         |d<   ||d<   |j                            d	d	
           |                    d          }|	                    t          j
        |d          d           |                    |           |                    d           dS # t          t          f$ r&}t                              d|           Y d}~dS d}~ww xY w)aq  Write refreshed credentials back to ~/.claude/.credentials.json.

    The optional *scopes* list (e.g. ``["user:inference", "user:profile", ...]``)
    is persisted so that Claude Code's own auth check recognises the credential
    as valid.  Claude Code >=2.1.81 gates on the presence of ``"user:inference"``
    in the stored scopes before it will use the token.
    r   r   r   r   )r   r   r   Nr%  r   T)parentsexist_okz.tmp   )indenti  z)Failed to write refreshed credentials: %s)r   r   r   r   r   r   parentmkdirwith_suffix
write_textr  r%   chmodr   r   r   r   )	r   r   r  r%  r   existingr   	_tmp_credr   s	            r   r"  r"  M  s    	i'*==IE 	Iz)"5"5w"5"G"GHHH ()&&
 &


 #)Jx  ((X/9R-R-R $,O#<X#FJx $.!td;;;))&11	TZ;;;gNNN)$$$W E E E@!DDDDDDDDDEs   C6D E
$EE
c                    | pt                      } | r1t          |           r"t                              d           | d         S | rGt                              d           t	          |           }|r|S t                              d           dS )zHResolve a token from Claude Code credential files, refreshing if needed.z-Using Claude Code credentials (auto-detected)r   u6   Claude Code credentials expired — attempting refreshuF   Token refresh failed — re-run 'claude setup-token' to reauthenticateN)r   r   r   r   r$  )r   r#  s     r   +_resolve_claude_code_token_from_credentialsr3  z  s    3133E $+E22 $DEEE]## _MNNN(//	 	]^^^4r0   	env_tokenc                     | r$t          |           rt          |t                    sdS |                    d          sdS t	          |          }|r"|| k    rt
                              d           |S dS )a  Prefer Claude Code creds when a persisted env OAuth token would shadow refresh.

    Hermes historically persisted setup tokens into ANTHROPIC_TOKEN. That makes
    later refresh impossible because the static env token wins before we ever
    inspect Claude Code's refreshable credential file. If we have a refreshable
    Claude Code credential record, prefer it over the static env OAuth token.
    Nr   zYPreferring Claude Code credential file over static env OAuth token so refresh can proceed)rv   r2   r   r   r3  r   r   )r4  r   r@   s      r   %_prefer_refreshable_claude_code_tokenr6    s      OI66 jPT>U>U t99^$$ t:5AAH H	))g	
 	
 	
 4r0   c                     t                      } t          j        dd                                          }|rt	          ||           }|r|S |S t          j        dd                                          }|rt	          ||           }|r|S |S t          |           }|r|S t          j        dd                                          }|r|S dS )u  Resolve an Anthropic token from all available sources.

    Priority:
      1. ANTHROPIC_TOKEN env var (OAuth/setup token saved by Hermes)
      2. CLAUDE_CODE_OAUTH_TOKEN env var
      3. Claude Code credentials (~/.claude.json or ~/.claude/.credentials.json)
         — with automatic refresh if expired and a refresh token is available
      4. ANTHROPIC_API_KEY env var (regular API key, or legacy fallback)

    Returns the token string or None.
    ANTHROPIC_TOKENr#   CLAUDE_CODE_OAUTH_TOKENANTHROPIC_API_KEYN)r   osgetenvrf   r6  r3  )r   token	preferredcc_tokenresolved_claude_tokenr   s         r   resolve_anthropic_tokenrA    s     )**E I',,2244E 9%GG	 	 y2B77==??H 9(EJJ	 	 HNN %$$ i+R006688G 4r0   c                  l   ddl } ddl}|                     d          }|st          d          	  |j        |dg           n# t
          t          f$ r Y dS w xY wt                      }|rt          |          r|d         S dD ]/}t          j
        |d                                          }|r|c S 0dS )	a  Run 'claude setup-token' interactively and return the resulting token.

    Checks multiple sources after the subprocess completes:
      1. Claude Code credential files (may be written by the subprocess)
      2. CLAUDE_CODE_OAUTH_TOKEN / ANTHROPIC_TOKEN env vars

    Returns the token string, or None if no credentials were obtained.
    Raises FileNotFoundError if the 'claude' CLI is not installed.
    r   Nr[   z\The 'claude' CLI is not installed. Install it with: npm install -g @anthropic-ai/claude-codezsetup-tokenr   )r9  r8  r#   )shutilrb   whichFileNotFoundErrorrc   KeyboardInterruptEOFErrorr   r   r;  r<  rf   )rC  rb   claude_pathr   env_varr.   s         r   run_oauth_setup_tokenrJ    s    MMM,,x((K 
H
 
 	

]34444x(   tt )**E $+E22 $]## B  i$$**,, 	JJJ	 4s   A AAr   r   z1https://console.anthropic.com/oauth/code/callbackz.org:create_api_key user:profile user:inferencez.anthropic_oauth.jsonc                     ddl } ddl}ddl}|                     |                    d                                        d                                          }|                     |                    |                                          	                                                              d                                          }||fS )z6Generate PKCE code_verifier and code_challenge (S256).r   N       =)
base64hashlibsecretsurlsafe_b64encodetoken_bytesr}   r  sha256r  digest)rN  rO  rP  verifier	challenges        r   _generate_pkcerW    s    MMMNNNNNN''(;(;B(?(?@@GGMMTTVVH((x(())0022 fTll6688  Yr0   c            	         ddl } ddl}t                      \  }}dt          dt          t
          |d|d}ddlm} d ||           }t                       t          d	           t                       t          d
           t          d           t          d           t          d           t                       t          d|            t                       	 |	                    |           t          d           n# t          $ r Y nw xY wt                       t          d           t                       	 t          d                                          }n# t          t          f$ r Y dS w xY w|st          d           dS |                    d          }|d         }	t!          |          dk    r|d         nd}
	 ddl}t%          j        dt          |	|
t          |d                                          }|j                            t.          |ddt1                       ddd          }|j                            |d          5 }t%          j        |                                                                          }ddd           n# 1 swxY w Y   n*# t          $ r}t          d |            Y d}~dS d}~ww xY w|                    d!d          }|                    d"d          }|                    d#d$          }|st          d%           dS t=          |                                  d&z            |d&z  z   }|||d'S )(z>Run Hermes-native OAuth PKCE flow and return credential state.r   NtruecodeS256)rZ  r   response_typeredirect_uriscopecode_challengecode_challenge_methodstate)r  z"https://claude.ai/oauth/authorize?z7Authorize Hermes with your Claude Pro/Max subscription.uc   ╭─ Claude Pro/Max Authorization ────────────────────╮u9   │                                                   │u9   │  Open this link in your browser:                  │u   ╰───────────────────────────────────────────────────╯z  z   (Browser opened automatically)z5After authorizing, you'll see a code. Paste it below.zAuthorization code: zNo code entered.#r   r#   authorization_code)r   r   rZ  ra  r]  code_verifierr   r   r   r  r  r     r  zToken exchange failed: r   r   r  r	  zNo access token in response.r   r
  )r   
webbrowserrW  _OAUTH_CLIENT_ID_OAUTH_REDIRECT_URI_OAUTH_SCOPESr  r  printopenr8   inputrf   rF  rG  rg   r)   r  r   r  r  r  r  _OAUTH_TOKEN_URLrq   r  r   r  r  r   r4   )r   rf  rU  rV  paramsr  auth_url	auth_codesplitsrZ  ra  r  exchange_datar  r  rl   r   r   r   r  r  s                        r   run_hermes_oauth_login_purers    s   KKK(**Hi %+#!'	 	F '&&&&&GIIf4E4EGGH	GGG	
CDDD	GGG	
oppp	
EFFF	
EFFF	  l  m  m  m	GGG	/x//	GGG!!!01111    
GGG	
ABBB	GGG0117799		x(   tt   !!!t__S!!F!9DVqF1IIbE
.)/%$
 $
   688 	 n$$ 2X,D,F,FXXX   % 
 
 ^##C#44 	6Z		 2 2 4 455F	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6   +++,,,ttttt ::nb11LJJ33ML$//J ,---t		d*++zD/@AM$&&  sa   $D 
DD?!E! !E65E6BJ% 9JJ% JJ%  J!J% %
K/KKc                  L   t                                           r	 t          j        t                               d                    } |                     d          r| S nD# t          j        t          t          f$ r%}t          
                    d|           Y d}~nd}~ww xY wdS )zKRead Hermes-managed OAuth credentials from ~/.hermes/.anthropic_oauth.json.r   r   r   z+Failed to read Hermes OAuth credentials: %sN)_HERMES_OAUTH_FILEr   r   r   r   r   r   r   r   r   r   )r   r   s     r   read_hermes_oauth_credentialsrv  m  s      "" K	K:0::G:LLMMDxx&& $gw7 	K 	K 	KLLFJJJJJJJJ	K4s   AA   B!<BB!c                     |                                  t          fddD                       rdS                     d          rdS dS )at  Detect AWS Bedrock model IDs that use dots as namespace separators.

    Bedrock model IDs come in two forms:
    - Bare:    ``anthropic.claude-opus-4-7``
    - Regional (inference profiles): ``us.anthropic.claude-sonnet-4-5-v1:0``

    In both cases the dots separate namespace components, not version
    numbers, and must be preserved verbatim for the Bedrock API.
    c              3   B   K   | ]}                     |          V  d S rE   rt   )rH   pr$   s     r   rJ   z'_is_bedrock_model_id.<locals>.<genexpr>  s1      
P
P15A
P
P
P
P
P
Pr0   )zglobal.zus.zeu.zap.zjp.Tz
anthropic.F)r$   rK   ru   )r   r$   s    @r   _is_bedrock_model_idrz  ~  s]     KKMME

P
P
P
P(O
P
P
PPP t%% t5r0   preserve_dotsc                 T   |                                  }|                    d          r| t          d          d         } |set          |           r| S |                                  }|                    d          s|                    d          r|                     dd          } | S )u  Normalize a model name for the Anthropic API.

    - Strips 'anthropic/' prefix (OpenRouter format, case-insensitive)
    - Converts dots to hyphens in version numbers (OpenRouter uses dots,
      Anthropic uses hyphens: claude-opus-4.6 → claude-opus-4-6), unless
      preserve_dots is True (e.g. for Alibaba/DashScope: qwen3.5-plus).
    - Preserves Bedrock model IDs (``anthropic.claude-opus-4-7``) and
      regional inference profiles (``us.anthropic.claude-*``) whose dots
      are namespace separators, not version separators.
    z
anthropic/Nzclaude-r!   r"   )r$   ru   r)   rz  r%   )r   r{  r$   _lowers       r   normalize_model_namer~    s     KKMME%% *c,''(() ,  && 	L Y'' 	,6+<+<\+J+J 	,MM#s++ELr0   tool_idc                 H    ddl }| sdS |                    dd|           }|pdS )zSanitize a tool call ID for the Anthropic API.

    Anthropic requires IDs matching [a-zA-Z0-9_-]. Replace invalid
    characters with underscores and ensure non-empty.
    r   Ntool_0z[^a-zA-Z0-9_-]_)resub)r  r  	sanitizeds      r   _sanitize_tool_idr    s;     III x(#w77I  r0   schemac                     | sdi dS ddl m}  || d          }t          |t                    sdi dS |                    d          dk    r0t          |                    d          t                    si |di i}|S )	a  Normalize tool schemas before sending them to Anthropic.

    Anthropic's tool schema validator rejects nullable unions such as
    ``anyOf: [{"type": "string"}, {"type": "null"}]`` that Pydantic/MCP
    commonly emits for optional fields. Tool optionality is represented by
    the parent ``required`` array, so we delegate to the shared
    ``strip_nullable_unions`` helper to collapse nullable unions to the
    non-null branch while preserving metadata like description/default.

    ``keep_nullable_hint=False`` because the Anthropic validator does not
    recognize the OpenAPI-style ``nullable: true`` extension and strict
    schema-to-grammar converters may reject unknown keywords.
    objecttype
propertiesr   )strip_nullable_unionsF)keep_nullable_hintr  r  )tools.schema_sanitizerr  r2   r   r   )r  r  r   s      r   _normalize_tool_input_schemar    s      4 333<<<<<<&&v%HHHJj$'' 4 333~~f))*Z^^L=Y=Y[_2`2`)5
5L"55
r0   toolsc                    | sg S g }t                      }| D ]}|                    di           }|                    dd          }|r ||v rt                              d|           P|r|                    |           |                    ||                    dd          t          |                    ddi d                    d	           |S )
z4Convert OpenAI tool definitions to Anthropic format.functionnamer#   uS   convert_tools_to_anthropic: duplicate tool name '%s' — dropping second occurrencedescription
parametersr  r  )r  r  input_schema)setr   r   warningaddappendr  )r  rl   
seen_namestfnr  s         r   convert_tools_to_anthropicr    s	    	FeeJ  UU:r""vvfb!!  	DJ&&NN1  
  	!NN4   66-448|hb%I%IJJ 
 
 	 	 	 	 Mr0   urlc                    t          | pd                                          } | sdddS |                     d          r|                     d          \  }}}d}|                    d          rZ|t	          d          d                             dd	          d
                                         }|                    d          r|}d||dS d| dS )zGConvert an OpenAI-style image URL/data URL into Anthropic image source.r#   r  )r  r  zdata:r   z
image/jpegN;r   r   zimage/rN  )r  
media_typer   )rx   rf   ru   	partitionr)   rg   )r  headerr  r   r  	mime_parts         r   _image_source_from_openai_urlr    s    
ciR..


 
 C *b)))
~~g 
--,,4!
W%% 	's7||}}-33C;;A>DDFFI##H-- '&
$
 
 	
 #&&&r0   partc                 r   | dS t          | t                    rd| dS t          | t                    sdt          |           dS |                     d          }|dk    rd|                     dd          d}nx|dv re|                     di           }t          |t                    r|                    d	d          nt          |pd          }d
t	          |          d}nt          |           }t          |                     d          t                    rd|vrt          | d                   |d<   |S )z?Convert a single OpenAI-style content part to Anthropic format.Nr`   r  r`   r  
input_textr#   >   	image_urlinput_imager  r  image)r  r   cache_control)r2   rx   r   r   r  )r  ptypeblockimage_valuer  s        r   "_convert_content_part_to_anthropicr    sG   |t$ .---dD!! 3D		222HHVE)/&"9M9M N N	.	.	.hh{B//,6{D,I,IekooeR(((sS^SdbdOeOe ,I#,N,NOOT

$((?++T22 =e7S7S!%d?&;!<!<oLr0   _depth_pathr9   r  r  c                   d}|k    rt          |           S t                      t          |           }|v rt          |           S t          | d          rS                    |           t          |                                 dz             }                    |           |S t          | t                    rM                    |           fd| 
                                D             }                    |           |S t          | t          t          f          r;                    |           fd| D             }                    |           |S t          | d          rZ                    |           fd	t          |           
                                D             }                    |           |S | S )
a|  Recursively convert SDK objects to plain Python data structures.

    Guards against circular references (``_path`` tracks ``id()`` of objects
    on the *current* recursion path) and runaway depth (capped at 20 levels).
    Uses path-based tracking so shared (but non-cyclic) objects referenced by
    multiple siblings are converted correctly rather than being stringified.
       N
model_dumpr   r  c                 B    i | ]\  }}|t          |d z             S r   r  _to_plain_datarH   krI   r  r  s      r   
<dictcomp>z"_to_plain_data.<locals>.<dictcomp>?  s2    aaa41a!^AfqjFFFaaar0   c                 :    g | ]}t          |d z             S r  r  )rH   rI   r  r  s     r   r   z"_to_plain_data.<locals>.<listcomp>D  s,    SSS.6A:UCCCSSSr0   __dict__c                 l    i | ]0\  }}|                     d           |t          |dz             1S )r  r   r  )ru   r  r  s      r   r  z"_to_plain_data.<locals>.<dictcomp>I  sT     
 
 
1<<$$
~a
%@@@
 
 
r0   )rx   r  idr   r  r  r  discardr2   r   r(   listtuplevars)r9   r  r  
_MAX_DEPTHobj_idrl   s    ``   r   r  r  %  s    J
5zz}YYF5zzul## 		& 0 0 2 26A:USSSf% 		&aaaaaSXS^S^S`S`aaaf%$'' 		&SSSSSUSSSfuj!! 		&
 
 
 
 
U))++
 
 

 	fLr0   messagec                    |                      d          }t          |t                    sg S g }|D ]}t          |t                    st	          |                     dd          pd                                                                          }|dvrf|                    t          j	        |                     |S )zEReturn Anthropic thinking blocks previously preserved on the message.reasoning_detailsr  r#   >   thinkingredacted_thinking)
r   r2   r  r   rx   rf   r$   r  copydeepcopy)r  raw_details	preserveddetail
block_types        r   "_extract_preserved_thinking_blocksr  S  s    ++122Kk4(( 	&(I 0 0&$'' 	FB//5266<<>>DDFF
>>>v..////r0   contentc                     t          | t                    s| S g }| D ](}t          |          }||                    |           )|S )zCConvert OpenAI-style multimodal content arrays to Anthropic blocks.)r2   r  r  r  )r  	convertedr  r  s       r   _convert_content_to_anthropicr  d  s[    gt$$ I $ $2488U###r0   messagesc                   $%& d}g }| D ]}|                     dd          }|                     dd          }|dk    r`t          |t                    rHt          d |D                       }|rd |D             }n"d	                    d
 |D                       }n|}|dk    rt          |          }	|rtt          |t                    r:t          |          }
t          |
t                    r|	                    |
           n%|	                    dt          |          d           |                     dg           D ]}|rt          |t                    s|                     di           }|                     dd          }	 t          |t                    rt          j        |          n|}n# t          j        t          f$ r i }Y nw xY w|	                    dt          |                     dd                    |                     dd          |d           |                     d          }t          d |	D                       }t          |t                    r|s|	                    dd|d           |	p|}|r|dk    rdddg}|                    d|d           |dk    rAt          |t                    r|nt          j        |          }|sd}dt          |                     d d                    |d!}t          |                     d"          t                    rt          |d"                   |d"<   |r|d#         d         dk    r|t          |d#         d         t                    r[|d#         d         rM|d#         d         d                              d$          dk    r"|d#         d                             |           n|                    d|gd           t          |t                    rJt          |          }|rt%          d% |D                       rdd&dg}|                    d|d           I|r)t          |t                    r|                                sd&}|                    d|d           t)                      %|D ]u}|d         dk    rgt          |d         t                    rL|d         D ]C}|                     d$          dk    r(%                    |                     d'                     Dv|D ]Q}|d         dk    rCt          |d         t                    r(%fd(|d         D             |d<   |d         s	dd)dg|d<   Rt)                      &|D ]u}|d         dk    rgt          |d         t                    rL|d         D ]C}|                     d$          dk    r(&                    |                     d                     Dv|D ]Q}|d         dk    rCt          |d         t                    r(&fd*|d         D             |d<   |d         s	dd+dg|d<   Rg }|D ]}|r|d#         d         |d         k    r|d         dk    r|d#         d         }|d         }t          |t                    r't          |t                    r|d	z   |z   |d#         d<   }t          |t                    r$t          |t                    r||z   |d#         d<   t          |t                    rd|dg}t          |t                    rd|dg}||z   |d#         d<   t          |d         t                    rd, |d         D             |d<   |d#         d         }|d         }t          |t                    r%t          |t                    r||z   |d#         d<   {t          |t                    r(t          |t                    r|d	z   |z   |d#         d<   t          |t                    rd|dg}t          |t                    rd|dg}||z   |d#         d<   |                    |           |}t-          d-          $t/          |          }t1          ||          pt3          |          }d}t5          t7          |          d.z
  d#d#          D ]%}||                              d          dk    r|} n&t9          |          D ]T\  }}|                     d          dk    s(t          |                     d          t                    sH|rg } |d         D ]}!t          |!t                    r|!                     d$          $vr|                     |!           D|!                     d/          s|!                     d0          ro|                     |!           | pdddg|d<   n!|s||k    r $fd1|d         D             }"|"pdd2dg|d<   ng } |d         D ]}!t          |!t                    r|!                     d$          $vr|                     |!           D|!                     d$          d3k    r+|!                     d0          r|                     |!           |!                     d/          r|                     |!           |!                     dd          }#|#r|                     d|#d           | pdddg|d<   |d         D ]D}!t          |!t                    r-|!                     d$          $v r|!                    d"d           EV||fS )4uq  Convert OpenAI-format messages to Anthropic format.

    Returns (system_prompt, anthropic_messages).
    System messages are extracted since Anthropic takes them as a separate param.
    system_prompt is a string or list of content blocks (when cache_control present).

    When *base_url* is provided and points to a third-party Anthropic-compatible
    endpoint, all thinking block signatures are stripped.  Signatures are
    Anthropic-proprietary — third-party endpoints cannot validate them and will
    reject them with HTTP 400 "Invalid signature in thinking block".

    When *model* is provided and matches the Kimi / Moonshot family (or
    *base_url* is a Kimi / Moonshot host), unsigned thinking blocks
    synthesised from ``reasoning_content`` are preserved on replayed
    assistant tool-call messages — Kimi requires the field to exist, even
    if empty.
    Nroleuserr  r#   r   c              3   j   K   | ].}t          |t                    |                    d           V  /dS )r  Nr2   r   r   rH   ry  s     r   rJ   z0convert_messages_to_anthropic.<locals>.<genexpr>  sQ          /0z!T?R?R EE/**           r0   c                 <    g | ]}t          |t                    |S rF   )r2   r   r  s     r   r   z1convert_messages_to_anthropic.<locals>.<listcomp>  s'    HHHAJq$4G4GHaHHHr0   
c              3   X   K   | ]%}|                     d           dk    |d         V  &dS )r  r`   Nr   r  s     r   rJ   z0convert_messages_to_anthropic.<locals>.<genexpr>  sC       ' '&'aeeFmmv6M6M&	6M6M6M6M' 'r0   	assistantr`   r  
tool_callsr  	argumentsz{}tool_user  r  )r  r  r  rl  reasoning_contentc              3   n   K   | ]0}t          |t                    o|                    d           dv V  1dS )r  r  r  Nr  r   s     r   rJ   z0convert_messages_to_anthropic.<locals>.<genexpr>  sU       ( ( 1d##Zf9Z(Z( ( ( ( ( (r0   r   r  )r  r  z(empty))r  r  toolz(no output)tool_resulttool_call_id)r  tool_use_idr  r  r   r  c              3      K   | ]^}t          |t                    rG|                    d           dk    0|                    dd                                          dk    V  _dS )r  r`   r#   N)r2   r   r   rf   r   s     r   rJ   z0convert_messages_to_anthropic.<locals>.<genexpr>  sv       + +a&&+ ,-55==F+B+B fb!!''))R/+B+B+B+B+ +r0   z(empty message)r  c                 t    g | ]4}|                     d           dk    s|                     d          v 2|5S )r  r  r  r  )rH   r   tool_result_idss     r   r   z1convert_messages_to_anthropic.<locals>.<listcomp>	  sL       55==J..!%%++2P2P 2P2P2Pr0   z(tool call removed)c                 t    g | ]4}|                     d           dk    s|                     d          v 2|5S )r  r  r  r  )rH   r   tool_use_idss     r   r   z1convert_messages_to_anthropic.<locals>.<listcomp>  sN       55==M11QUU=5I5I\5Y5Y 5Y5Y5Yr0   z(tool result removed)c                 j    g | ]0}t          |t                    r|                    d           dv .|1S )r  r  r  r   s     r   r   z1convert_messages_to_anthropic.<locals>.<listcomp>>  sJ     $ $ $ *1d 3 3$89fIj8j8j 8j8j8jr0   r  r   	signaturer   c                 l    g | ]0}t          |t                    r|                    d           v .|1S )r  r  )rH   r   _THINKING_TYPESs     r   r   z1convert_messages_to_anthropic.<locals>.<listcomp>  sJ       "1d++01f0P0P 0P0P0Pr0   z(thinking elided)r  )r   r2   r  rK   r   r  r  extendr  rx   r   r   r   r   r>   r  insertr  allrf   r  r  	frozensetr   r   r   ranger)   	enumeratepop)'r  ry   r   r   rl   r*   r  r  	has_cacheblocksconverted_contenttcr  argsparsed_argsr  _already_has_thinking	effectiveresult_contentr  converted_blocksr  fixedprev_contentcurr_contentprev_blockscurr_blocks_is_third_party_preserve_unsigned_thinkinglast_assistant_idxiidxnew_contentr   strippedthinking_textr  r  r  s'                                       @@@r   convert_messages_to_anthropicr  q  s   , FF t@ t@uuVV$$%%	2&&8'4(( !    4;       	  HHHHHFF!YY ' '+2' ' '  FF !;7::F Jgt,, J(Eg(N(N%!"3T:: 9&7888MM63w<<"H"HIIIeeL"--   B!5!5 VVJ++vvk400%6@s6K6K"U$*T"2"2"2QUKK,j9 % % %"$KKK%&+BFF4,<,<==FF62..(	     0 !"&9 : :$' ( (( ( ( % %! +S11 V:O Va*BS!T!TUUU)'I B	R&,i@@A	MM;9EEFFF6>>(27C(@(@YWWdjQXFYFYN! /!.%0~r1J1JKK) K
 !%%00$77 H/3Ao4F/G/GO, 	J2Jv&&00vbz)4d;; 12Jy) 1 2Jy)!,0088MIIr
9%,,[9999v;-HHIII gt$$ 	@<WEE# Qs + +)+ + + ( ( Q
 .4=N$O$O#P MM66FGGHHHH  ,z'377 , ,+MM6g>>???? eeO B BV9:a	lD#A#A9 B B99V$$55#''		-(@(@AAA Q QV9##
1Y<(F(F#   9  AiL
 Y< Q)/9N O OP) 55L 6 6V9##
1Y<(F(F#9 6 699V$$
22 $$UYYt__555 S SV9:a	lD#A#A   9  AiL
 Y< S)/9P Q QR) E ) ) (	U2Yv&!F)33yF""$Ry3 |lC00 
GZc5R5R 
G+7$+>+ME"Ii((d33 G
<QU8V8V G+7,+FE"Ii(( ",44 P17(N(N'O!,44 P17(N(N'O+7,+FE"Ii(( a	lD11 $ $#$Y<$ $ $AiL $Bi	2	lk400 
EZT5R5R 
E+6+DE"Ii((S11 Ejc6R6R E+6+=+KE"Ii(( "+s33 N06'L'L&M!+s33 N06'L'L&M+6+DE"Ii((LLOOOOF.   ABBO8BBO 	!511 	5*844  
 3v;;?B++  !9==  K//!"E 0 F## ;- ;-Q55==K''z!%%	:J:JD/Q/Q'& 1	P Ky\ 	& 	&!!T** aeeFmm?.R.R&&q)))55%% v  ""1%%%%&OFI+N+N*OAiLL 	P'9 9 9   Y<  H $VAT(U(U'VAiLL
 Ky\ T T!!T** aeeFmm?.R.R&&q)))55==$777uuV}} .#**1---UU;'' T&&q)))) %&EE*b$9$9M$ T#**FM+R+RSSS&OFI+N+N*OAiL 9 	- 	-A!T"" -quuV}}'G'Got,,,	- 6>s   +F44GG
max_tokensreasoning_configtool_choiceis_oauth	fast_modec                    t          ||	|           \  }}|rt          |          ng }t          | |          } t          || |          }|r||k    rt	          |dz
  d          }|rdt
          d}t          |t                    r|g|z   }n"t          |t                    r
|r|d|dg}n|g}|D ]}t          |t                    r|
                    d          dk    rs|
                    dd          }|                    d	d
          }|                    dd
          }|                    dd          }|                    dd          }||d<   |r|D ]}d|v rt          |d         z   |d<   |D ]}|
                    d          }t          |t                    r|D ]}t          |t                    ro|
                    d          dk    r8d|v r4|d                             t                    st          |d         z   |d<   h|
                    d          dk    rd|v r	 | ||d}|r||d<   |r]||d<   |dk    s|ddi|d<   nH|dk    rddi|d<   n:|dk    r|                    dd           nt          |t                    rd|d|d<   t          |	|           }|rt          |t                    r|s|
                    d           d!urd"|                                 vrt          |
                    d#d$                                                    }t"          
                    |d%          }t%          |           rBd&d'd(|d)<   t&          
                    |d$          }|d*k    rt)          |           sd+}d#|i|d,<   n#d |d-|d)<   d|d.<   t	          ||d/z             |d0<   t+          |           rd1D ]}|                    |d           |
rt-          |	          sd2|                    d3i           d4<   t          t1          |	|5                    }|r|                    t4                     |                    t8                     d6d7                    |          i|d8<   |S )9uZ  Build kwargs for anthropic.messages.create().

    Naming note — two distinct concepts, easily confused:
      max_tokens     = OUTPUT token cap for a single response.
                       Anthropic's API calls this "max_tokens" but it only
                       limits the *output*.  Anthropic's own native SDK
                       renamed it "max_output_tokens" for clarity.
      context_length = TOTAL context window (input tokens + output tokens).
                       The API enforces: input_tokens + max_tokens ≤ context_length.
                       Stored on the ContextCompressor; reduced on overflow errors.

    When *max_tokens* is None the model's native output ceiling is used
    (e.g. 128K for Opus 4.6, 64K for Sonnet 4.6).

    When *context_length* is provided and the model's native output ceiling
    exceeds it (e.g. a local endpoint with an 8K window), the output cap is
    clamped to context_length − 1.  This only kicks in for unusually small
    context windows; for full-size models the native output cap is always
    smaller than the context window so no clamping happens.
    NOTE: this clamping does not account for prompt size — if the prompt is
    large, Anthropic may still reject the request.  The caller must detect
    "max_tokens too large given prompt" errors and retry with a smaller cap
    (see parse_available_output_tokens_from_error + _ephemeral_max_output_tokens).

    When *is_oauth* is True, applies Claude Code compatibility transforms:
    system prompt prefix, tool name prefixing, and prompt sanitization.

    When *preserve_dots* is True, model name dots are not converted to hyphens
    (for Alibaba/DashScope anthropic-compatible endpoints: qwen3.5-plus).

    When *base_url* points to a third-party Anthropic-compatible endpoint,
    thinking block signatures are stripped (they are Anthropic-proprietary).

    When *fast_mode* is True, adds ``extra_body["speed"] = "fast"`` and the
    fast-mode beta header for ~2.5x faster output throughput on Opus 4.6.
    Currently only supported on native Anthropic endpoints (not third-party
    compatible ones).
    )ry   r   )r{  )r<   r   r`   r  r  r#   zHermes AgentzClaude CodezHermes agentzhermes-agentr\   zNous Researchr   r  r  r  r  r  )r   r  r  r   r  autoNr  requiredrK   noner  )r  r  enabledFhaikueffortr   r   adaptive
summarized)r  displayr  r   r   output_config)r  budget_tokenstemperaturer   r  )r*  top_ptop_kfast
extra_bodyspeedr   r   r   extra_headers)r  r  r~  rB   r   _CLAUDE_CODE_SYSTEM_PREFIXr2   r  rx   r   r   r%   _MCP_TOOL_PREFIXru   r   r   r$   THINKING_BUDGETrN   ADAPTIVE_EFFORT_MAPrR   rV   r   
setdefaultr   r  r   r  _FAST_MODE_BETAr   )r   r  r  r  r  r  r  r{  r<   ry   r  r   r   anthropic_messagesanthropic_toolseffective_max_tokenscc_blockr  r`   r  msgr  r   _is_kimi_codingr$  budgetadaptive_effort_sampling_keybetass                                r   build_anthropic_kwargsrA    s   h "?85" " "F <AH0777bO mDDDE
 BE.    :.??">A#5q99  %!",FGGfd## 	 Z&(FF$$ 	  	  @ @AFFZF  	% 	%E%&& %599V+<+<+F+Fyy,,||NMBB||NMBB||NMBB||O[AA $f  	C' C CT>>#3d6l#BDL & 		! 		!Cggi((G'4(( !$ ! !E!%.. ! 99V,,
::v#(=#;#;<L#M#M Q0@5=0Pf"YYv..-??MUZDZDZ  &* F  "!x J)w&  K$7%+V$4F=!!J&&%+UOF=!!F""JJw%%%%S)) 	J-3[$I$IF=!2 /x??O PJ'7>> P P	**%77G5;;==<X<X)--hAABBHHJJF$((66F*511 P&+& &z" #6"9"9&("K"K #g--6LU6S6S-&+Oo+'' /8&%Q%Qz"()}%'*+?$'O'O|$  && ,> 	, 	,MJJ}d++++  F;HEE F7=,++G4 /!5
 
 
    	,LL*+++_%%%#3SXXe__"EMr0   rE   )NN)F)NFFNNFF)d__doc__r  r   loggingr;  r   rb   pathlibr   hermes_constantsr   typingr   r   r   r   r	   utilsr
   r   r   __annotations__r   	getLogger__name__r   r3  r4  rQ   rL   rU   r'   r&   rx   r4   r/   r;   rB   r3   rN   rR   rV   r   r   r   r6  r   ri   rY   rn   r1  r2  rq   rv   rz   r   r   r   r   r   r   r   r  r   r5   r   r   r   r   r   r   r   r$  r"  r3  r6  rA  rJ  rg  rm  rh  ri  ru  r  rW  rs  rv  rz  r~  r  r  r  r  r  r  r  r  r  r  rA  rF   r0   r   <module>rK     s  
 
 
    				            , , , , , , 3 3 3 3 3 3 3 3 3 3 3 3 3 3 A A A A A A A A    	 	 	 
	8	$	$!5DNN    * 
 !=  "0  !             !/  8 #* S S    *,Xc] , , , ,: %)  SM 		   >Bs Bt B B B B
=# =$ = = = =CC CD C C C C2   @  + 
 )
   !) ,0 HSM 0 0 0)S ) ) ) )2 Y  &# & & & &     8!# ! ! ! !t      TsTz Td T T T T 	5cDj 	5T 	5 	5 	5 	5 sTz #* PT    8:cDj :T : : : :6mC$J m4 m m m m" "'  Dj  
#Y	   D c.
 "'c. c. c.c.c. c.
 c. c. c. c.L!3 ! ! ! !H6Xd38n5M 6 6 6 6r%htCH~&> % % % %P#    *d38n * * * * * JO =7 =7 =7 =7$ =7SWX[]`X`Sa =7 =7 =7 =7@S#X 8C=    4 "*E *E *E*E*E *E
 TN*E 
*E *E *E *EZ xS#X7O [cdg[h    S $sTWx.AY ^fgj^k    ,)# ) ) ) )X%x} % % % %X : A I @$_&&)@@ 
 
 
 
 
_Xd38n%= _ _ _ _D	xS#X'? 	 	 	 	"     (  D S    :
!s 
!s 
! 
! 
! 
! c3h    6d4j T$Z    >'s 'tCH~ ' ' ' ',S Xd38n5M    2 12$ + + +# +# +(3- +SV + + + +\S#X 4SRUXCW    "
3 
3 
 
 
 
  G G4jGDjG :G 8C=$t*$%	G G G G`
 "&$(!&R RR4jR DJR 	R
 tCH~.R #R R R SMR DjR R R 
#s(^R R R R R Rr0   