+
    i                     |  a  R~ tM0 t R t^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RIH	t	 ^ RI
Ht ^ RIHtHtHtHtHt  ^ RIt]P*                  ! ]4      tRRRR	R
RRR/tRRRRR
R
RRRR/t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/tRtR! R" ltR# R$ ltR%R&.tR'R(.tR)t Rs!] ^ k R* R+ lt"R,t#R-t$R. R/ lt%R0 R1 lt&R2 R3 lt'R4 R5 lt(RR6 R7 llt)R8 R9 lt*R: R; lt+R< R= lt,R>R?/R@ RA llt-RB RC lt.RDR/RE RF llt/RRG RH llt0RI RJ lt1RRK RL llt2RM RN lt3RO RP lt4RQt5RRt6RSt7RTt8]	! 4       RU,          t9RV RW lt:RX RY lt;RZ R[ lt<R\ R] lt=R^ R_ lt>R` Ra lt?RRb Rc llt@Rd Re ltARf Rg ltBRh Ri ltCRj Rk ltDRl Rm ltERn Ro ltFRp^ RqR/Rr Rs lltGRt Ru ltHRv Rw ltIRx Ry ltJRRz R{ lltKRR| R} lltLR#   ] d    Rt EL|i ; i)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)SimpleNamespace)AnyDictListOptionalTuplexhighi }  highi>  medium@  lowi  maxminimalzclaude-opus-4-6i  zclaude-sonnet-4-6i   z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-sonneti    zclaude-3-5-haikuzclaude-3-opus   zclaude-3-sonnetzclaude-3-haikuc                0    V ^8  d   QhR\         R\        /#    modelreturnstrint)formats   "4/home/ubuntu/hermes-agent/agent/anthropic_adapter.py__annotate__r   F   s      S S     c                    V P                  4       pRp\        p\        P                  4        F,  w  rEWA9   g   K  \	        V4      \	        V4      8  g   K(  TpTpK.  	  V# )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".
 )lower_ANTHROPIC_DEFAULT_OUTPUT_LIMIT_ANTHROPIC_OUTPUT_LIMITSitemslen)r   mbest_keybest_valkeyvals   &     r   _get_anthropic_max_outputr*   F   sS     	AH.H,2248C3x=0HH 5 Or   c                0    V ^8  d   QhR\         R\        /# r   r   bool)r   s   "r   r   r   X   s     3 3s 3t 3r   c                x   a  \         ;QJ d    V 3R lR 4       F  '       g   K   R# 	  R# ! V 3R lR 4       4      # )zAReturn True for Claude 4.6 models that support adaptive thinking.c              3   ,   <"   T F	  qS9   x  K  	  R # 5iN ).0vr   s   & r   	<genexpr>._supports_adaptive_thinking.<locals>.<genexpr>Z   s     2>aEz>s   TF)z4-6z4.6)any)r   s   fr   _supports_adaptive_thinkingr7   X   s,    32>23323232>222r   zinterleaved-thinking-2025-05-14z&fine-grained-tool-streaming-2025-05-14zclaude-code-20250219zoauth-2025-04-20z2.1.74c                $    V ^8  d   QhR\         /# r   r   r   )r   s   "r   r   r   r   s     ) )S )r   c                    ^ RI p R F  p V P                  VR.RR^R7      pVP                  ^ 8X  d   VP                  P	                  4       '       d]   VP                  P	                  4       P                  4       ^ ,          pV'       d$   V^ ,          P                  4       '       d   Vu # K  K  K  K  	  \        #   \         d     K  i ; i)a"  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.
Nz	--versionT)capture_outputtexttimeout)claudeclaude-code)	
subprocessrun
returncodestdoutstripsplitisdigit	Exception_CLAUDE_CODE_VERSION_FALLBACK)_spcmdresultversions       r   _detect_claude_code_versionrN   r   s     (	WWk"#$  F   A%&--*=*=*?*? ----/557:wqz1133"N  47 +@% ) )(  		s$   AB;6B;
B;'B;;C
	C
z9You are Claude Code, Anthropic's official CLI for Claude.mcp_c                $    V ^8  d   QhR\         /# r9   r:   )r   s   "r   r   r      s     & &# &r   c                 2    \         f   \        4       s \         # )zKLazily detect the installed Claude Code version when OAuth headers need it.)_claude_code_version_cacherN   r1   r   r   _get_claude_code_versionrS      s     ")%@%B"%%r   c                0    V ^8  d   QhR\         R\        /# )r   r(   r   r,   )r   s   "r   r   r      s        r   c                L    V '       g   R# V P                  R4      '       d   R# R# )zCheck if the key is an OAuth/setup token (not a regular Console API key).

Regular API keys start with 'sk-ant-api'. Everything else (setup-tokens
starting with 'sk-ant-oat', managed keys, JWTs, etc.) needs Bearer auth.
Fz
sk-ant-apiT)
startswith)r(   s   &r   _is_oauth_tokenrW      s     
~~l##r   c                >    V ^8  d   QhR\         R,          R\        /# r   base_urlNr   r,   )r   s   "r   r   r      s      t  r   c                j    V '       g   R# V P                  R4      P                  4       pRV9   d   R# R# )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)rstripr    rZ   
normalizeds   & r   "_is_third_party_anthropic_endpointr`      s/     %++-J*$r   c                >    V ^8  d   QhR\         R,          R\        /# rY   r,   )r   s   "r   r   r      s      C$J 4 r   c                    V '       g   R# V P                  R4      P                  4       pVP                  R4      ;'       g    VP                  R4      # )a4  Return True for Anthropic-compatible providers that require Bearer auth.

Some third-party /anthropic endpoints implement Anthropic's Messages API but
require Authorization: Bearer instead 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/anthropic)r]   r    rV   r^   s   & r   _requires_bearer_authrc      sP     %++-J  !CD  
H]H],I r   c                0    V ^8  d   QhR\         R\         /# )r   api_keyrZ   r:   )r   s   "r   r   r      s     5. 5.C 5.3 5.r   c                n   \         f   \        R4      h^ RIHp RV! RRR7      /pV'       d   WR&   \	        V4      '       d,   WR&   \
        '       d   R	R
P                  \
        4      /VR&   M\        V4      '       d,   WR&   \
        '       d   R	R
P                  \
        4      /VR&   Mw\        V 4      '       d=   \
        \        ,           pWR&   R	R
P                  V4      RR\        4        R2RR/VR&   M*WR&   \
        '       d   R	R
P                  \
        4      /VR&   \         P                  ! R/ VB # )zoCreate an Anthropic client, auto-detecting setup-tokens vs API keys.

Returns an anthropic.Anthropic instance.
zpThe 'anthropic' package is required for the Anthropic provider. Install it with: pip install 'anthropic>=0.39.0')Timeoutr>   g      @g      $@)r>   connectrZ   
auth_tokenzanthropic-beta,default_headersre   z
user-agentclaude-cli/ (external, cli)zx-appclir1   )_anthropic_sdkImportErrorhttpxrg   rc   _COMMON_BETASjoinr`   rW   _OAUTH_ONLY_BETASrS   	Anthropic)re   rZ   rg   kwargs	all_betass   &&   r   build_anthropic_clientrx      s;   
 ?
 	
  	75$7F %zX&&  '|=)9388M;R(SF$%	+H	5	5
 $y=)9388M;R(SF$%		!	! "$55	&|chhy1K(@(B'CCSTU%
 ! $y=)9388M;R(SF$%##-f--r   c                \    V ^8  d   QhR\         \        \        \        3,          ,          /# r9   r   r   r   r   )r   s   "r   r   r      s       htCH~&> r   c            	     8   \         P                  ! 4       R,          R,          p V P                  4       '       d    \        P                  ! V P                  RR7      4      pVP                  R4      pV'       d[   \        V\        4      '       dE   VP                  RR4      pV'       d+   RVRVP                  RR4      R	VP                  R	^ 4      R
R/# R# R#   \        P                  \        \        3 d"   p\        P                  RT4        Rp?R# Rp?ii ; i)a  Read refreshable Claude Code OAuth credentials from ~/.claude/.credentials.json.

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encodingclaudeAiOauthaccessTokenr   refreshToken	expiresAtsourceclaude_code_credentials_filez.Failed to read ~/.claude/.credentials.json: %sN)r   homeexistsjsonloads	read_textget
isinstancedictJSONDecodeErrorOSErrorIOErrorloggerdebug)	cred_pathdata
oauth_dataaccess_tokenes        r   read_claude_code_credentialsr      s     		i'*==I	N::i1171CDD/2JjT::)~~mR@%|&
~r(J#Z^^K%C "@	   $$gw7 	NLLI1MM	Ns#   >C :/C *)C  D8DDc                :    V ^8  d   QhR\         \        ,          /# r9   r   r   )r   s   "r   r   r     s      # r   c                    \         P                  ! 4       R,          p V P                  4       '       dx    \        P                  ! V P                  RR7      4      pVP                  RR4      p\        V\        4      '       d'   VP                  4       '       d   VP                  4       # R# R#   \        P                  \        \        3 d"   p\        P                  RT4        Rp?R# Rp?ii ; i)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   r   r   rE   r   r   r   r   r   )claude_jsonr   primary_keyr   s       r   read_claude_managed_keyr     s    ))+.K	A::k33W3EFD((?B7K+s++0A0A0C0C"((**  $$gw7 	ALL<a@@	As   A#B, B, , C-C((C-c                R    V ^8  d   QhR\         \        \        3,          R\        /# r   credsr   )r   r   r   r-   )r   s   "r   r   r   (  s"     * *d38n * *r   c                    ^ RI pV P                  R^ 4      pV'       g   \        V P                  R4      4      # \        VP                  4       R,          4      pW2R,
          8  # )zACheck if Claude Code credentials have a non-expired access token.Nr   r     i`  )timer   r-   r   )r   r   
expires_atnow_mss   &   r   is_claude_code_token_validr   (  sQ    ;*JEIIm,-- t#$F&())r   use_jsonFc                ^    V ^8  d   QhR\         R\        R\        \         \        3,          /# )r   refresh_tokenr   r   )r   r-   r   r   )r   s   "r   r   r   7  s.     =7 =7 =7$ =7SWX[]`X`Sa =7r   c                  ^ RI p^ RIp^ RIpV '       g   \        R4      hRpV'       d.   \        P
                  ! RRRV RV/4      P                  4       pRpM1VP                  P                  RRRV RV/4      P                  4       pRpR	R
.pRpV EF  p	VP                  P                  V	VRVRR\        4        R2/RR7      p
 VP                  P                  V
^
R7      ;_uu_ 4       p\        P                  ! VP                  4       P                  4       4      pRRR4       XP'                  RR4      pT'       g   \        R4      hTP'                  RT 4      pTP'                  RR4      pRTRTR\)        TP                  4       R,          4      TR,          ,           /u # 	  Ve   Vh\        R4      h  + '       g   i     L; i  \          d%   pTp\"        P%                  RY4        Rp?EKc  Rp?ii ; i)zIRefresh an Anthropic OAuth token without mutating local credential files.Nzrefresh_token is required$9d1c250a-e61b-44d9-88ed-5944d1962f5e
grant_typer   	client_idapplication/jsonz!application/x-www-form-urlencodedz*https://platform.claude.com/v1/oauth/token,https://console.anthropic.com/v1/oauth/tokenContent-Type
User-Agentrl   rm   POSTr   headersmethodr>   z(Anthropic token refresh failed at %s: %sr   r   z3Anthropic refresh response was missing access_token
expires_in  expires_at_msr   zAnthropic token refresh failed)r   urllib.parseurllib.request
ValueErrorr   dumpsencodeparse	urlencoderequestRequestrS   urlopenr   readdecoderH   r   r   r   r   )r   r   r   urllibr   r   content_typetoken_endpoints
last_errorendpointreqresprL   excr   next_refreshr   s   &$               r   refresh_anthropic_oauth_purer   7  s   4556Izz/]
  68	 	
 *||%%/]'
  68	 	
 ; 	56O J#nn$$,D,F+GGWX  % 
	''R'88DDIIK$6$6$89 9 zz."5RSSzz/=AZZd3
L\St!34
T8IJ
 	
/ $: 
5
66) 98 	JLLCXS	s6   %G	)3F6G	6GG	G		G8G33G8c                h    V ^8  d   QhR\         \        \        3,          R\        \        ,          /# r   r   r   r   r   )r   s   "r   r   r   w  s&      S#X 8C= r   c                ^   V P                  RR4      pV'       g   \        P                  R4       R#  \        VRR7      p\	        VR,          VR,          VR	,          4       \        P                  R
4       VR,          #   \
         d"   p\        P                  RT4        Rp?R# Rp?ii ; i)z6Attempt to refresh an expired Claude Code OAuth token.r   r   u-   No refresh token available — cannot refreshNFr   r   r   r   z.Successfully refreshed Claude Code OAuth tokenz'Failed to refresh Claude Code token: %s)r   r   r   r   _write_claude_code_credentialsrH   )r   r   	refreshedr   s   &   r   _refresh_oauth_tokenr   w  s    IInb1MDE0O	&n%o&o&	

 	EF(( >Bs   AB   B,B''B,scopesc          
      b    V ^8  d   QhR\         R\         R\        R\        \        ,          RR/# )r   r   r   r   r   r   N)r   r   r   list)r   s   "r   r   r     sE     (E (E(E(E (E
 TN(E 
(Er   c               \   \         P                  ! 4       R,          R,          p / pVP                  4       '       d'   \        P                  ! VP                  RR7      4      pRV RVRV/pVe   W6R	&   M(R
V9   d"   R	VR
,          9   d   VR
,          R	,          VR	&   WeR
&   VP                  P                  RRR7       VP                  \        P                  ! V^R7      RR7       VP                  R4       R#   \        \        3 d"   p\        P                  RT4        Rp?R# Rp?ii ; i)a]  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_okindent  z)Failed to write refreshed credentials: %s)r   r   r   r   r   r   parentmkdir
write_textr   chmodr   r   r   r   )r   r   r   r   r   existingr   r   s   &&&$    r   r   r     s    		i'*==IEzz)"5"5w"5"GHH <M&


 #)x (X/9R-R $,O#<X#FJx $.!td;TZZ;gNW E@!DDEs   C9 B:C9 9D+
D&&D+c                ~    V ^8  d   QhR\         \        \        \        3,          ,          R\         \        ,          /# r   rz   )r   s   "r   r   r     s.      xS#X7O [cdg[h r   c                *   T ;'       g    \        4       p V '       d0   \        V 4      '       d   \        P                  R4       V R,          # V '       d@   \        P                  R4       \	        V 4      pV'       d   V# \        P                  R4       R# )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_credentialsr     sl    3313E+E22DE]##MN(/	]^r   c                    V ^8  d   QhR\         R\        \        \         \        3,          ,          R\        \         ,          /# )r   	env_tokenr   r   )r   r   r   r   )r   s   "r   r   r     s6      S $sTWx.AY ^fgj^k r   c                    V '       d(   \        V 4      '       d   \        V\        4      '       g   R# VP                  R4      '       g   R# \	        V4      pV'       d   W 8w  d   \
        P                  R4       V# R# )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)rW   r   r   r   r   r   r   )r   r   resolveds   && r   %_prefer_refreshable_claude_code_tokenr     s^     OI66jPT>U>U99^$$:5AHH)g	
 r   c                F    V ^8  d   QhR\         \        ,          R\        /# )r   tokenr   r   )r   s   "r   r   r     s      hsm s r   c                X   T ;'       g    RP                  4       p V '       g   R# \        P                  ! RR4      P                  4       pV'       d	   W8X  d   R# \        P                  ! RR4      P                  4       pV'       d	   W 8X  d   R# \        4       pV'       d;   VP	                  R4      V 8X  d%   \        VP	                  R4      ;'       g    R	4      # \        4       pV'       d	   W@8X  d   R
# \        P                  ! RR4      P                  4       pV'       d	   WP8X  d   R# R# )zDBest-effort source classification for an Anthropic credential token.r   noneANTHROPIC_TOKENanthropic_token_envCLAUDE_CODE_OAUTH_TOKENclaude_code_oauth_token_envr   r   claude_code_credentialsclaude_json_primary_api_keyANTHROPIC_API_KEYanthropic_api_key_envunknown)rE   osgetenvr   r   r   r   )r   r   cc_env_tokenr   managed_keyre   s   &     r   get_anthropic_token_sourcer    s    [[b!E		+R0668IY'$996;AACL-,(*E=)U2599X&CC*CDD)+K{+,ii+R0668G7#&r   c                :    V ^8  d   QhR\         \        ,          /# r9   r   )r   s   "r   r   r     s     ) )# )r   c                    \        4       p \        P                  ! RR4      P                  4       pV'       d   \	        W4      pV'       d   V# V# \        P                  ! RR4      P                  4       pV'       d   \	        W04      pV'       d   V# V# \        V 4      pV'       d   V# \        P                  ! RR4      P                  4       pV'       d   V# R# )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.
r   r   r   r   N)r   r   r   rE   r   r   )r   r   	preferredcc_tokenresolved_claude_tokenre   s         r   resolve_anthropic_tokenr    s     )*E II',224E9%G	 yy2B7==?H9(J	 HN$$ ii+R0668Gr   c                :    V ^8  d   QhR\         \        ,          /# r9   r   )r   s   "r   r   r   %  s     % %x} %r   c                    ^ RI p ^ RIpV P                  R4      pV'       g   \        R4      h VP	                  VR.4       \        4       pT'       d   \        T4      '       d
   TR,          # R F4  p\        P                  ! TR4      P                  4       pT'       g   K2  Tu # 	  R#   \
        \        3 d     R# i ; i)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.
Nr?   z\The 'claude' CLI is not installed. Install it with: npm install -g @anthropic-ai/claude-codezsetup-tokenr   r   )r   r   )shutilrA   whichFileNotFoundErrorrB   KeyboardInterruptEOFErrorr   r   r   r   rE   )r  rA   claude_pathr   env_varr)   s         r   run_oauth_setup_tokenr  %  s     ,,x(KH
 	
]34
 )*E+E22]## Bii$**,3J B
  x( s   B) )B>=B>r   r   z1https://console.anthropic.com/oauth/code/callbackz.org:create_api_key user:profile user:inferencez.anthropic_oauth.jsonc                $    V ^8  d   QhR\         /# r9   )tuple)r   s   "r   r   r   X  s     
 
 
r   c                 L   ^ RI p ^ RIp^ RIpV P                  VP	                  ^ 4      4      P                  R4      P                  4       pV P                  VP                  VP                  4       4      P                  4       4      P                  R4      P                  4       pW43# )z6Generate PKCE code_verifier and code_challenge (S256).N   =)
base64hashlibsecretsurlsafe_b64encodetoken_bytesr]   r   sha256r   digest)r  r  r  verifier	challenges        r   _generate_pkcer   X  s    ''(;(;B(?@GGMTTVH((x()002fTl668  r   c                \    V ^8  d   QhR\         \        \        \        3,          ,          /# r9   rz   )r   s   "r   r   r   e  s#     _ _Xd38n%= _r   c                    ^ RI p ^ RIp\        4       w  r#RRR\        RRR\        R\
        RVR	R
RV/p^ RIHp RV! V4       2p\        4        \        R4       \        4        \        R4       \        R4       \        R4       \        R4       \        4        \        RV 24       \        4         VP                  V4       \        R4       \        4        \        R4       \        4         \        R4      P                  4       pT'       g   \        R4       R# TP                  R4      pT^ ,          p	\!        T4      ^8  d
   T^,          MRp
 ^ RIp\$        P&                  ! RRR\        RT	RT
R\        RT/4      P)                  4       pTP*                  P-                  \.        TRRRR \1        4        R!2/R"R#7      pTP*                  P3                  T^R$7      ;_uu_ 4       p\$        P4                  ! TP7                  4       P9                  4       4      pRRR4       XP;                  R&R4      pTP;                  R'R4      pTP;                  R(R)4      pT'       g   \        R*4       R# \=        T P                  4       R+,          4      TR+,          ,           pR&TR'TR,T/#   \         d     ELi ; i  \        \        3 d     R# i ; i  + '       g   i     L; i  \         d   p\        R%T 24        Rp?R# Rp?ii ; i)-z>Run Hermes-native OAuth PKCE flow and return credential state.Ncodetruer   response_typeredirect_uriscopecode_challengecode_challenge_methodS256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code_verifierr   r   r   rl   rm   r   r   r   zToken exchange failed: r   r   r   r   zNo access token in response.r   r   )r   
webbrowserr   _OAUTH_CLIENT_ID_OAUTH_REDIRECT_URI_OAUTH_SCOPESr   r   printopenrH   inputrE   r  r  rF   r$   r   r   r   r   r   r   _OAUTH_TOKEN_URLrS   r   r   r   r   r   r   )r   r/  r  r  paramsr   auth_url	auth_codesplitsr#  r+  r   exchange_datar   r   rL   r   r   r   r   r   s                        r   run_hermes_oauth_login_purer<  e  s   (*H 	%+)	F '3If4E3FGH	G	
CD	G	
op	
EF	
EF	  l  m	G	Bxj/	G!01 
G	
AB	G01779	  !__S!F!9DVqF1IbE

.)DU/X$
  68 	 nn$$ 2,D,F+GGWX  % 
 ^^##C#44ZZ		 2 2 45F 5 ::nb1LJJ3ML$/J,-		d*+zD/@AM q   x( B 54 's+,s[   2J" .J4 BK &3KK "J10J14K	K	K	K K L*K>>Lc                :    V ^8  d   QhR\         \        ,          /# r9   r   )r   s   "r   r   r     s       r   c                     \        4       p V '       g   R# V R,          pV R,          pV R,          p\        WV4       \        WV4       \        R4       V# )a  Run Hermes-native OAuth PKCE flow for Claude Pro/Max subscription.

Opens a browser to claude.ai for authorization, prompts for the code,
exchanges it for tokens, and stores them in ~/.hermes/.anthropic_oauth.json.

Returns the access token on success, None on failure.
Nr   r   r   zAuthentication successful!)r<  _save_hermes_oauth_credentialsr   r3  )rL   r   r   r   s       r   run_hermes_oauth_loginr@    sS     )*F.)L?+M?+M"<N"<N	
&'r   c                @    V ^8  d   QhR\         R\         R\        RR/# )r   r   r   r   r   Nr   )r   s   "r   r   r     s0     G G GS GY\ Gae Gr   c                H   RV RVRV/p \         P                  P                  RRR7       \         P                  \        P
                  ! V^R7      RR7       \         P                  R	4       R#   \        \        3 d"   p\        P                  R
T4        Rp?R# Rp?ii ; i)z:Save OAuth credentials to ~/.hermes/.anthropic_oauth.json.r   r   r   Tr   r   r~   r   r   z+Failed to save Hermes OAuth credentials: %sN)_HERMES_OAUTH_FILEr   r   r   r   r   r   r   r   r   r   )r   r   r   r   r   s   &&&  r   r?  r?    s     	|]D
G!!''t'D%%djja&@7%S  'W GBAFFGs   A#A/ /B! BB!c                \    V ^8  d   QhR\         \        \        \        3,          ,          /# r9   rz   )r   s   "r   r   r     s      	 	xS#X'? 	r   c                 P   \         P                  4       '       dH    \        P                  ! \         P	                  RR7      4      p V P                  R4      '       d   V #  R# R#   \        P                  \        \        3 d"   p\        P                  RT4        Rp?R# Rp?ii ; i)zKRead Hermes-managed OAuth credentials from ~/.hermes/.anthropic_oauth.json.r~   r   r   z+Failed to read Hermes OAuth credentials: %sN)rC  r   r   r   r   r   r   r   r   r   r   )r   r   s     r   read_hermes_oauth_credentialsrF    s      ""	K::0::G:LMDxx&& '  $$gw7 	KLLFJJ	Ks   A A$ A$ $ B%B  B%c                :    V ^8  d   QhR\         \        ,          /# r9   r   )r   s   "r   r   r     s      HSM r   c                    \        4       p V '       d   V P                  R4      '       g   R#  \        V R,          RR7      p\        VR,          VR,          VR,          4       \	        VR,          VR,          VR,          4       \
        P                  R4       VR,          #   \         d"   p\
        P                  R	T4        Rp?R# Rp?ii ; i)
zRefresh the Hermes-managed OAuth token using the stored refresh token.

Returns the new access token, or None if refresh fails.
r   NTr   r   r   r   z)Successfully refreshed Hermes OAuth tokenz(Failed to refresh Hermes OAuth token: %s)rF  r   r   r?  r   r   r   rH   )r   r   r   s      r   refresh_hermes_oauth_tokenrI    s    
 *+E		.11D0.!
	 	'n%o&o&	

 	'n%o&o&	

 	@A(( D?CCDs   A5B# #C.C

Cc                <    V ^8  d   QhR\         R\        R\         /# )r   r   preserve_dotsr   r,   )r   s   "r   r   r     s!       D S r   c                    V P                  4       pVP                  R4      '       d   V \        R4      R p V'       g   V P                  RR4      p V # )uB  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).
z
anthropic/N.-)r    rV   r$   replace)r   rK  r    s   && r   normalize_model_namerP    sL     KKME%%c,'() c3'Lr   c                0    V ^8  d   QhR\         R\         /# )r   tool_idr   r:   )r   s   "r   r   r   0  s     
! 
!s 
!s 
!r   c                \    ^ RI pV '       g   R# VP                  RRV 4      pT;'       g    R# )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.
Ntool_0z[^a-zA-Z0-9_-]_)resub)rR  rV  	sanitizeds   &  r   _sanitize_tool_idrY  0  s.     (#w7I   r   c                    V ^8  d   QhR\         \        \        3,          R\        \         \        \        3,          ,          /# r   partr   r   )r   s   "r   r   r   =  s2      $sCx. XdSVX[S[nE] r   c           	     \   V P                  R/ 4      p\        V\        4      '       d   VP                  RR4      M
\        V4      p\        V\        4      '       d   VP	                  4       '       g   R# VP	                  4       pVP                  R4      '       dZ   VP                  R4      w  r4pV'       d>   RV9   d7   VR,          P                  R	^4      ^ ,          ;'       g    R
pRRRRRRVRV//# VP                  R4      '       g   VP                  R4      '       d   RRRRRRV//# R# )zGConvert an OpenAI-style image block to Anthropic's image source format.	image_urlurlr   Ndata:rj   z;base64:   NN;	image/pngtypeimager   r  
media_typer   zhttp://zhttps://)r   r   r   r   rE   rV   	partitionrF   )r\  
image_datar_  headersepr   rf  s   &      r   '_convert_openai_image_part_to_anthropicrk  =  s   +r*J'1*d'C'C*..
#ZCc3syy{{
))+C
~~gMM#.T9&))#q1!4CCJH *D  ~~i  CNN:$>$>Gs
 	
 r   c                h    V ^8  d   QhR\         R\        \        \        \         3,          ,          /# r[  r   r   r   r   )r   s   "r   r   r   ^  s'      # (4S>:R r   c                    \        V \        4      '       Ed)   V P                  R 4      pVR8X  dS   R RRV P                  RR4      /p\        V P                  R4      \        4      '       d   \        V R,          4      VR&   V# VR8X  d   \        V 4      # VR8X  d#   V P                  R4      '       d   \        V 4      # VR8X  dh   V P                  R4      '       dQ   V P                  R4      ;'       g    V P                  R	4      ;'       g    R
pR RRR RR	VRV P                  RR4      //# VR8X  d   \        V 4      #  R# V e   R RR\	        V 4      /# R# )rd  r=   r   cache_controlr^  re  r   r   mimeTyperf  rc  r  tool_resultN)r   r   r   rk  r   )r\  ptypeblockrf  s   &   r   '_convert_user_content_part_to_anthropicrt  ^  sI   $ F?VVTXXfb-ABE$((?3T::)-d?.C)Do&LK:4@@G 2 2:G 0 0*-VV,1GVV;JH *DHHVR0  M!: "  
	D	22r   c                \    V ^8  d   QhR\         \        ,          R\         \        ,          /# )r   toolsr   )r   r   )r   s   "r   r   r   {  s"      d4j T$Z r   c                    V '       g   . # . pV  F`  pVP                  R/ 4      pVP                  RVP                  RR4      RVP                  RR4      RVP                  RRRR	/ /4      /4       Kb  	  V# )
z4Convert OpenAI tool definitions to Anthropic format.functionnamer   descriptioninput_schema
parametersrd  object
properties)r   append)rv  rL   tfns   &   r   convert_tools_to_anthropicr  {  s{    	FUU:r"BFF62&266-4BFF<&(LRT1UV
 	  Mr   c                R    V ^8  d   QhR\         R\        \         \         3,          /# )r   r_  r   )r   r   )r   s   "r   r   r     s"     ' 's 'tCH~ 'r   c                   \        T ;'       g    R4      P                  4       p V '       g   RRRR/# V P                  R4      '       d   V P                  R4      w  rpRpVP                  R4      '       dM   V\	        R4      R P                  R^4      ^ ,          P                  4       pVP                  R	4      '       d   TpRR
RVRV/# RRRV /# )zGConvert an OpenAI-style image URL/data URL into Anthropic image source.r   rd  r_  r`  rj   z
image/jpegNrb  zimage/r  rf  r   )r   rE   rV   rg  r$   rF   )r_  ri  rU  r   rf  	mime_parts   &     r   _image_source_from_openai_urlr    s    
ciiR.


 Cub))
~~g--,4!
W%%s7|}-33C;A>DDFI##H--&
H*D
 	
 E5#&&r   c                h    V ^8  d   QhR\         R\        \        \        \         3,          ,          /# r[  rm  )r   s   "r   r   r     s'      S Xd38n5M r   c                V   V f   R# \        V \        4      '       d   RRRV /# \        V \        4      '       g   RRR\        V 4      /# V P                  R4      pVR8X  d   RRRV P                  RR4      /pMqVR9   d`   V P                  R/ 4      p\        V\        4      '       d   VP                  RR4      M\        T;'       g    R4      pRRR	\	        V4      /pM\        V 4      p\        V P                  R
4      \        4      '       d   R
V9  d   \        V R
,          4      VR
&   V# )z?Convert a single OpenAI-style content part to Anthropic format.Nrd  r=   
input_textr   r^  r_  re  r   ro  >   r^  input_image)r   r   r   r   r  )r\  rr  rs  image_valuer_  s   &    r   "_convert_content_part_to_anthropicr    s   |$--dD!!D	22HHVE!'&"9M N	.	.hh{B/,6{D,I,IkooeR(sS^SdSdbdOe(,I#,NOT
$((?+T22e7S!%d?&;!<oLr   _depth_pathc                ^    V ^8  d   QhR\         R\        R\        \        ,          R\         /# )r   valuer  r  r   )r   r   r   set)r   s   "r   r   r     s-     + +# +# +(3- +SV +r   c                  ^pW8  d   \        V 4      # Vf   \        4       p\        V 4      pWB9   d   \        V 4      # \        V R4      '       dH   VP	                  V4       \        V P                  4       V^,           VR7      pVP                  V4       V# \        V \        4      '       d[   VP	                  V4       V P                  4        UUu/ uF  w  rgV\        Wq^,           VR7      bK  	  pppVP                  V4       V# \        V \        \        34      '       dH   VP	                  V4       V  Uu. uF  p\        Wq^,           VR7      NK  	  ppVP                  V4       V# \        V R4      '       d}   VP	                  V4       \        V 4      P                  4        UUu/ uF3  w  rgVP                  R4      '       d   K  V\        Wq^,           VR7      bK5  	  pppVP                  V4       V# V # u uppi u upi u uppi )ah  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.

model_dump)r  r  __dict__rU  )r   r  idhasattradd_to_plain_datar  discardr   r   r#   r   r  varsrV   )r  r  r  
_MAX_DEPTHobj_idrL   kr3   s   &$$     r   r  r    s    J5z}YF5zul##		& 0 0 26A:USf%		&SXS^S^S`aS`41!^AqjFFS`af%$''		&MRSU.A:UCUSfuj!!		& U))+
+<<$ AA~a
%@@+ 	 

 	fL# b
 T

s    G:8H )H	Hc                    V ^8  d   QhR\         \        \        3,          R\        \         \        \        3,          ,          /# )r   messager   )r   r   r   r   )r   s   "r   r   r     s0      S#X 4SRUXCW r   c                |   V P                  R4      p\        V\        4      '       g   . # . pV F  p\        V\        4      '       g   K  \	        VP                  RR4      ;'       g    R4      P                  4       P                  4       pVR9  d   Ke  VP                  \        P                  ! V4      4       K  	  V# )zEReturn Anthropic thinking blocks previously preserved on the message.reasoning_detailsrd  r   >   thinkingredacted_thinking)
r   r   r   r   r   rE   r    r  copydeepcopy)r  raw_details	preserveddetail
block_types   &    r   "_extract_preserved_thinking_blocksr    s    ++12Kk4((	&(I&$''FB/5526<<>DDF
>>v./  r   c                0    V ^8  d   QhR\         R\         /# )r   contentr   )r   )r   s   "r   r   r     s     
 
3 
3 
r   c                    \        V \        4      '       g   V # . pV  F%  p\        V4      pVf   K  VP                  V4       K'  	  V# )zCConvert OpenAI-style multimodal content arrays to Anthropic blocks.)r   r   r  r  )r  	convertedr\  rs  s   &   r   _convert_content_to_anthropicr    sI    gt$$I248U#  r   c                    V ^8  d   QhR\         \        ,          R\        \        \        ,          \         \        ,          3,          /# )r   messagesr   )r   r   r	   r   r   )r   s   "r   r   r     s6     t t4jt
8C=$t*$%tr   c                ~   Rp. pV  EFu  pVP                  RR4      pVP                  RR4      pVR8X  d   \        V\        4      '       d   \        ;QJ d    R V 4       F  '       g   K   RM	  R	M! R V 4       4      pV'       d+   V Uu. uF  p\        V\        4      '       g   K  VNK  	  ppMR
P                  R V 4       4      pMTpK  VR8X  Ed   \        V4      pV'       dh   \        V\        4      '       d4   \        V4      p	\        V	\        4      '       d   VP                  V	4       MVP                  RRR\        V4      /4       VP                  R. 4       F  p
V
'       d   \        V
\        4      '       g   K#  V
P                  R/ 4      pVP                  RR4      p \        V\        4      '       d   \        P                  ! V4      MTpVP                  RRR\        V
P                  RR4      4      RVP                  RR4      RV/4       K  	  T;'       g    TpV'       d   VR8X  d   RRRR/.pVP                  RRRV/4       EKR  VR8X  EdO   \        V\        4      '       d   TM\        P                   ! V4      pV'       g   RpRRR\        VP                  RR4      4      RV/p\        VP                  R4      \        4      '       d   \	        VR,          4      VR&   V'       d   VR",          R,          R8X  d   \        VR",          R,          \        4      '       db   VR",          R,          '       dL   VR",          R,          ^ ,          P                  R4      R8X  d!   VR",          R,          P                  V4       MVP                  RRRV./4       EK  \        V\        4      '       dm   \        V4      pV'       d;   \"        ;QJ d    R V 4       F  '       d   K   R	M	  RM! R V 4       4      '       d   RRRR/.pVP                  RRRV/4       EK*  V'       d-   \        V\        4      '       d   VP%                  4       '       g   RpVP                  RRRV/4       EKx  	  \'        4       pV Fz  pVR,          R8X  g   K  \        VR,          \        4      '       g   K2  VR,           F;  pVP                  R4      R8X  g   K  VP)                  VP                  R4      4       K=  	  K|  	  V F  pVR,          R8X  g   K  \        VR,          \        4      '       g   K2  VR,           Uu. uF3  pVP                  R4      R8w  g   VP                  R4      V9   g   K1  VNK5  	  upVR&   VR,          '       d   K  RRRR /.VR&   K  	  \'        4       pV Fz  pVR,          R8X  g   K  \        VR,          \        4      '       g   K2  VR,           F;  pVP                  R4      R8X  g   K  VP)                  VP                  R4      4       K=  	  K|  	  V F  pVR,          R8X  g   K  \        VR,          \        4      '       g   K2  VR,           Uu. uF3  pVP                  R4      R8w  g   VP                  R4      V9   g   K1  VNK5  	  upVR&   VR,          '       d   K  RRRR!/.VR&   K  	  . pV EF/  pV'       Ed   VR",          R,          VR,          8X  Ed   VR,          R8X  d   VR",          R,          pVR,          p\        V\        4      '       d3   \        V\        4      '       d   VR
,           V,           VR",          R&   K  \        V\        4      '       d,   \        V\        4      '       d   VV,           VR",          R&   K  \        V\        4      '       d   RRRV/.p\        V\        4      '       d   RRRV/.pVV,           VR",          R&   EK*  VR",          R,          pVR,          p\        V\        4      '       d-   \        V\        4      '       d   VV,           VR",          R&   EK  \        V\        4      '       d4   \        V\        4      '       d   VR
,           V,           VR",          R&   EK  \        V\        4      '       d   RRRV/.p\        V\        4      '       d   RRRV/.pVV,           VR",          R&   EK  VP                  V4       EK2  	  TpW3# u upi   \        P                  \        3 d    / p ELXi ; iu upi u upi )#a  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).
Nroleuserr  r   systemc              3   t   "   T F.  p\        V\        4      '       g   K  VP                  R 4      x  K0  	  R# 5i)ro  N)r   r   r   r2   ps   & r   r4   0convert_messages_to_anthropic.<locals>.<genexpr>  s+       4;qz!T?R*AEE/**Gs   88TF
c              3   b   "   T F%  qP                  R 4      R8X  g   K  VR,          x  K'  	  R# 5i)rd  r=   N)r   r  s   & r   r4   r    s(      '+2aeeFmv6M	&		7s   //	assistantrd  r=   
tool_callsrx  	argumentsz{}tool_user  ry  r5  z(empty)toolz(no output)rq  tool_use_idtool_call_idro  c              3      "   T FX  p\        V\        4      '       g   K  VP                  R 4      R8X  g   K3  VP                  RR4      P                  4       R8H  x  KZ  	  R# 5i)rd  r=   r   N)r   r   r   rE   )r2   bs   & r   r4   r  a  sQ      +)Aa& 0+,55=F+B 0fb!'')R/)s   A"A"+A"z(empty message)z(tool call removed)z(tool result removed))r   r   r   r6   r   rs   r  r  extendr  r   r   r   r   r   rY  r   allrE   r  r  )r  r  rL   r%   r  r  	has_cacher  blocksconverted_contenttcr  argsparsed_args	effectiveresult_contentrq  converted_blockstool_result_idsrs  r  tool_use_idsfixedprev_contentcurr_contentprev_blockscurr_blockss   &                          r   convert_messages_to_anthropicr    s    FFuuVV$%%	2&8'4((C  4; CCC  4;  	 )0HAJq$4GaaFHF!YY '+2' F !;7:Fgt,,(Eg(N%!"3T::&78MM6663w<"HIeeL"-B!5!5VVJ+vvk40%6@s6K6K$**T"2QUK J+BFF4,<=BFF62.[	  .  ))'I	R$ffi@A	MM6;	9EF6>(27C(@(@WdjjQXFYN!!.0~r1JK>K
 !%%0$77/3Ao4F/GO, 2Jv&&0vbz)4d;;2Jy))2Jy)!,008MIr
9%,,[9vvy;-HI gt$$<WE#ss +)+sss +)+ ( (
 &,VV=N$O#P MM6696FGH z'377+MM669g>?w | eOV9:a	lD#A#A999V$5#''		-(@A & 
 V9#
1Y<(F(F 9%A55=J.!%%+2P %AiL
 Y<<!'9N OP)  5LV9#
1Y<(F(F999V$
2 $$UYYt_5 & 
 V9:a	lD#A#A 9%A55=M1QUU=5I\5Y %AiL
 Y<<!'9P QR)  E5U2Yv&!F)3yF"$Ry3 |lC00Zc5R5R+7$+>+ME"Ii(d33
<QU8V8V+7,+FE"Ii( ",44)/(N'O!,44)/(N'O+7,+FE"Ii( $Bi	2	lk400ZT5R5R+6+DE"Ii(S11jc6R6R+6+=+KE"Ii( "+s33(.'L&M!+s33(.'L&M+6+DE"Ii(LLOC D F>{ I2 ,,j9 %"$K%D(s6   d)d+.d
.d5=d51.d:$d:d21d2c                n   V ^8  d   QhR\         R\        \        ,          R\        \        \        ,          ,          R\        \        ,          R\        \        \         \
        3,          ,          R\        \         ,          R\        R\        R	\        \        ,          R
\        \         \
        3,          /
# )r   r   r  rv  
max_tokensreasoning_configtool_choiceis_oauthrK  context_lengthr   )r   r   r   r   r   r   r-   )r   s   "r   r   r     s     u uu4ju DJu 	u
 tCH~.u #u u u SMu 
#s(^ur   c	                p   \        V4      w  rV'       d   \        V4      M. p\        WR7      p T;'       g    \        V 4      pV'       d   W8  d   \	        V^,
          ^4      pV'       Ed   RRR\
        /p\        V	\        4      '       d   V.V	,           p	M*\        V	\        4      '       d   V	'       d
   VRRRV	/.p	MV.p	V	 F  p\        V\        4      '       g   K  VP                  R4      R8X  g   K3  VP                  RR4      pVP                  RR4      pVP                  RR4      pVP                  RR	4      pVP                  R
R4      pWR&   K  	  V'       d*   V F#  pRV9   g   K  \        VR,          ,           VR&   K%  	  V
 F  pVP                  R4      p\        V\        4      '       g   K,  V F  p\        V\        4      '       g   K  VP                  R4      R8X  dE   RV9   d>   VR,          P                  \        4      '       g   \        VR,          ,           VR&   Ks  Ku  VP                  R4      R8X  g   K  RV9   g   K  K  	  K  	  RV RV
RV/pV	'       d   V	VR&   V'       da   VVR&   VR8X  g   Vf	   RR/VR&   MHVR8X  d	   RR/VR&   M9VR8X  d   VP                  RR4       M\        V\        4      '       d
   RRRV/VR&   V'       d   \        V\        4      '       d   VP                  R4      RJd   RV P                  4       9  d   \        VP                  R R!4      4      P                  4       p\         P                  VR"4      p\#        V 4      '       d%   RR#/VR$&   R \$        P                  VR!4      /VR%&   V# RRR&V/VR$&   ^VR'&   \	        VVR(,           4      VR&   V# ))a(  Build kwargs for anthropic.messages.create().

When *max_tokens* is None, the model's native output limit is used
(e.g. 128K for Opus 4.6, 64K for Sonnet 4.6).  If *context_length*
is provided, the effective limit is clamped so it doesn't exceed
the context window.

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).
)rK  rd  r=   r   zHermes AgentzClaude CodezHermes agentzhermes-agentr@   zNous Researchru   ry  r  r  rq  r  r   r  r  r  rv  autoNr  requiredr6   r   r  enabledFhaikueffortr   r   adaptiver  output_configbudget_tokenstemperaturer   )r  r  rP  r*   r   _CLAUDE_CODE_SYSTEM_PREFIXr   r   r   r   r   rO  _MCP_TOOL_PREFIXrV   popr    THINKING_BUDGETr7   ADAPTIVE_EFFORT_MAP)r   r  rv  r  r  r  r  rK  r  r  anthropic_messagesanthropic_toolseffective_max_tokenscc_blockrs  r=   r  msgr  rv   r  budgets   &&&&&&&&&             r   build_anthropic_kwargsr    sv   0 "?x!HF;@07bO DE%II)B5)I .?">A#5q9 xFF,FGfd##Z&(F$$ @AFZF E%&&599V+<+Fyy,||NMB||NMB||NMB||O[A $f  'T>#3d6l#BDL (
 &Cggi(G'4(($E!%.. 99V,
:v#(=#;#;<L#M#M0@5=0Pf $N"YYv.-?MUZDZ  % & 	&*F !x)w& K$7%+V$4F=!J&%+UOF=!F"JJw%S))%+VV[$IF=! J'7>>	*%7G5;;=<X)--hABHHJF$((6F*511&,j%9z"155fhG+' M '-i&%Qz"()}%'*+?$'O|$Mr   c                R    V ^8  d   QhR\         R\        \        \        3,          /# )r   strip_tool_prefixr   )r-   r	   r   r   )r   s   "r   r   r   4  s(     : :: ?C :r   c                   . p. p. p. pV P                    EF8  pVP                  R8X  d   VP                  VP                  4       K2  VP                  R8X  dR   VP                  VP                  4       \        V4      p\        V\        4      '       d   VP                  V4       K  K  VP                  R8X  g   K  VP                  pV'       d.   VP                  \        4      '       d   V\        \        4      R pVP                  \        VP                  R\        V\        P                  ! VP                   4      R7      R7      4       EK;  	  RR	RR
RRRR	/p	V	P#                  V P$                  R	4      p
\        V'       d   RP'                  V4      MRT;'       g    RV'       d   RP'                  V4      MRRT;'       g    RR7      V
3# )a@  Normalize Anthropic response to match the shape expected by AIAgent.

Returns (assistant_message, finish_reason) where assistant_message has
.content, .tool_calls, and .reasoning attributes.

When *strip_tool_prefix* is True, removes the ``mcp_`` prefix that was
added to tool names for OAuth Claude Code compatibility.
r=   r  r  Nrx  )ry  r  )r  rd  rx  end_turnstopr  r  lengthstop_sequencer  z

)r  r  	reasoningreasoning_contentr  )r  rd  r  r=   r  r  r   r   ry  rV   r  r$   r   r  r   r   r5  r   stop_reasonrs   )responser  
text_partsreasoning_partsr  r  rs  
block_dictry  stop_reason_mapfinish_reasons   &&         r   normalize_anthropic_responser  4  s    JOJ!!::ejj)ZZ:%""5>>2'.J*d++!((4 ,ZZ:%::D T__5E%F%FC 0123xx#,!"&**U[["9	 "2 	FLh	O $''(<(<fEM 	-7DIIj)T!))T6Efkk/24"/774	
 		 	r   c                V    V ^8  d   Qh/ ^ \         9   d   \        \        ,          ;R&   # )r   rR   )__conditional_annotations__r   r   )r   s   "r   r   r      s$     
 
\ 1 0HSM 0]
r   r0   )F)NFFN)Nr  __doc__r  r   loggingr   pathlibr   hermes_constantsr   typesr   typingr   r   r   r   r	   	anthropicro   rp   	getLogger__name__r   r  r  r"   r!   r*   r7   rr   rt   rI   rR   rN   r  r  rS   rW   r`   rc   rx   r   r   r   r   r   r   r   r   r  r  r  r0  r6  r1  r2  rC  r   r<  r@  r?  rF  rI  rP  rY  rk  rt  r  r  r  r  r  r  r  r  r  r   )r  s   @r   <module>r     s=  
    	  , ! 3 3& 
		8	$E65(D%NU
Fh	5u  &&&&&&55555' 0 #* $3 &,   !) ,0  0)2 Y  &5.p<*=7 =7@*(E
 "(EV,:)X%X : A I @$&)@@ 
_D.G	J$
!B:',2+ +$ +\"
tnup: :w(  Ns   F. .	F;:F;