
    Yj)                      d Z ddlm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	Z	ddl
mZmZmZ ddlmZmZ ddlmZ ddlmZmZmZmZmZmZ ddlmZ dd	lmZ dd
lmZ ddl m!Z!m"Z" ddl#m$Z% ddl#m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3  ej4        e5          Z6dedZ7dZ8dZ9dZ: e;h d          Z<dZ=dZ>dZ?dZ@e@ dZAdZBdZCdZDdZEeBeCeDeEhZFdZGdZHdZIdZJ e;h d           ZKdfd&ZLe G d' d(                      ZMdgd*ZNdhd.ZOdid1ZPdjd4ZQdkd7ZRdld9ZSdmd=ZTdnd?ZUdodAZVdpdqdCZWdpdrdGZXdsdIZYdtdKZZdudLZ[ddMdvdOZ\dPZ]dwdTZ^ G dU dV          Z_dxdXZ`dydYZadzd[Zbdzd\Zcd]d^d{dbZdd|dcZed}ddZfdS )~z<Persistent multi-credential pool for same-provider failover.    )annotationsN)	dataclassfieldsreplace)datetimetimezone)Path)AnyDictListOptionalSetTuple)OPENROUTER_BASE_URL)load_env)
get_secret)is_borrowed_credential_source$sanitize_borrowed_credential_payload)'CODEX_ACCESS_TOKEN_REFRESH_SKEW_SECONDSPROVIDER_REGISTRY_auth_store_lock_codex_access_token_is_expiring_decode_jwt_claims_load_auth_store_load_provider_state_resolve_kimi_base_url_resolve_zai_base_url_save_auth_store_save_provider_state_store_provider_stateread_credential_poolwrite_credential_poolreturnOptional[dict]c                 F    	 ddl m}   |             S # t          $ r Y dS w xY w)z.Load config.yaml, returning None on any error.r   load_configN)hermes_cli.configr'   	Exceptionr&   s    JC:\Users\server\AppData\Local\hermes\hermes-agent\agent\credential_pool.py_load_config_safer+   -   sG    111111{}}   tts    
  ok	exhausteddead>   invalid_grantinvalid_tokentoken_revokedtoken_invalidatedunauthorized_clientrefresh_token_reusediQ oauthapi_keymanualz:device_code
fill_firstround_robinrandom
least_usedi,    zcustom:>   tlsscope	client_id
expires_in
token_typeobtained_atagent_key_idsecret_sourceportal_base_urlagent_key_reusedsecret_fingerprintagent_key_expires_inagent_key_obtained_atproviderstrtokenr
   	auth_typec                    | dk    r1t          |t                    r|                    d          rt          S t          |pt                    S )zHInfer pool auth metadata for token formats with one unambiguous meaning.	anthropicz
sk-ant-oat)
isinstancerK   
startswithAUTH_TYPE_OAUTHAUTH_TYPE_API_KEY)rJ   rL   rM   s      r*   _normalize_pool_auth_typerT      sS     	Kuc"" 	 \** 	  y--...    c                     e Zd ZU ded<   ded<   ded<   ded<   ded<   ded<   ded	<   d
Zded<   d
Zded<   d
Zded<   d
Zded<   d
Zded<   d
Z	ded<   d
Z
ded<   d
Zded<   d
Zded<   d
Zded<   d
Zded<   d
Zded<   d
Zded<   d
Zded<   dZded<   d
Zded<   d  Zd*d"Zed+d&            Zd,d'Zed-d(            Zed.d)            Zd
S )/PooledCredentialrK   rJ   idlabelrM   intprioritysourceaccess_tokenNOptional[str]refresh_tokenlast_statusOptional[float]last_status_atOptional[int]last_error_codelast_error_reasonlast_error_messagelast_error_reset_atbase_url
expires_atexpires_at_mslast_refreshinference_base_url	agent_keyagent_key_expires_atr   request_countDict[str, Any]extrac                l    | j         i | _         t          | j        | j        | j                  | _        d S N)rq   rT   rJ   r]   rM   selfs    r*   __post_init__zPooledCredential.__post_init__   s6    :DJ2MN
 
rU   namec                    |t           v r| j                            |          S t          dt	          |           j         d|          )N'z' object has no attribute )_EXTRA_KEYSrq   getAttributeErrortype__name__)ru   rw   s     r*   __getattr__zPooledCredential.__getattr__   sJ    ;:>>$'''Xd!4XXPTXXYYYrU   payloadr#   'PooledCredential'c                   d t          |           D             }fd|D             }d|v r3t          |d         t                    rt          |d                   |d<   fdt          D             }||d<   |                    dt          j                    j        d d                    |                    d	                    d	|                     |                    d
t                     |                    dd           |                    d	t                     |                    dd            | dd|i|S )Nc                2    h | ]}|j         d k    |j         S )rJ   rw   .0fs     r*   	<setcomp>z-PooledCredential.from_dict.<locals>.<setcomp>   s&    KKK!af
6J6Jqv6J6J6JrU   c                D    i | ]}|v |                     |          S  )r{   r   kr   s     r*   
<dictcomp>z.PooledCredential.from_dict.<locals>.<dictcomp>   s*    GGGa!w,,7;;q>>,,,rU   rb   c                :    i | ]}|v |         ||         S rs   r   r   s     r*   r   z.PooledCredential.from_dict.<locals>.<dictcomp>   s1    ___1qG||PQ
H^GAJH^H^H^rU   rq   rX      rY   r\   rM   r[   r   r]    rJ   r   )r   rP   rK   _parse_absolute_timestamprz   
setdefaultuuiduuid4hexr{   rS   SOURCE_MANUAL)clsrJ   r   field_namesdatarq   s     `   r*   	from_dictzPooledCredential.from_dict   sD   KKvc{{KKKGGGG;GGGt##
48H3I3(O(O#%>tDT?U%V%VD!"_______Wdjll.rr2333Xx!@!@AAA%6777
A&&&-000+++s--H----rU   c                   h d}i }t          |           D ]6}|j        dv rt          | |j                  }|	|j        |v r
|||j        <   7| j                                        D ]\  }}||||<   t          || j                  S )N>   r`   rb   rd   re   rf   rg   >   rq   rJ   )r   rw   getattrrq   itemsr   rJ   )ru   _ALWAYS_EMITresult	field_defvaluer   vs          r*   to_dictzPooledCredential.to_dict   s    
 
 
 "$ 	/ 	/I~!666D).11E INl$B$B).y~&J$$&& 	 	DAq}q	3FDMJJJrU   c           	     V   | j         dk    r| j        | j        f| j        | j        ffD ]j\  }}t          |t                    rP|                                r<t          j	        |t          | dd           |          r|                                c S kdS t          | j        pd          S )Nnousr>   )r>   ri   r   )rJ   rm   rn   r]   ri   rP   rK   stripauth_mod_nous_invoke_jwt_is_usabler   )ru   rL   ri   s      r*   runtime_api_keyz PooledCredential.runtime_api_key   s    =F"" !:;"DO4& ) )!z
 uc**	)	) !;%dGT::#-  	) !;;==(((24$*+++rU   c                B    | j         dk    r| j        p| j        S | j        S )Nr   )rJ   rl   rh   rt   s    r*   runtime_base_urlz!PooledCredential.runtime_base_url   s'    =F""*;dm;}rU   )rw   rK   )rJ   rK   r   rp   r#   r   )r#   rp   )r#   rK   )r#   r^   )r~   
__module____qualname____annotations__r_   r`   rb   rd   re   rf   rg   rh   ri   rj   rk   rl   rm   rn   ro   rq   rv   r   classmethodr   r   propertyr   r   r   rU   r*   rW   rW      s        MMMGGGJJJNNNMMMKKK#'M''''!%K%%%%&*N****%)O))))'+++++(,,,,,+/////"H"""" $J$$$$#'M''''"&L&&&&(,,,,,#I####*.....M E    
 
 
Z Z Z Z
 . . . [. K K K K* , , , X,*    X  rU   rW   fallbackc                    t          |           }dD ]V}|                    |          }t          |t                    r*|                                r|                                c S W|S )N)emailpreferred_usernameupn)r   r{   rP   rK   r   )rL   r   claimskeyr   s        r*   label_from_tokenr      sh    &&F5 ! !

3eS!! 	!ekkmm 	!;;==   OrU   entriesList[PooledCredential]rZ   c                >    t          d | D             d          dz   S )Nc              3  $   K   | ]}|j         V  d S rs   r[   r   entrys     r*   	<genexpr>z!_next_priority.<locals>.<genexpr>  s$      445444444rU   )default   )max)r   s    r*   _next_priorityr     s)    44G444bAAAAEErU   r\   boolc                    | pd                                                                 }|t          k    p|                    t           d          S )Nr   :)r   lowerr   rQ   )r\   
normalizeds     r*   _is_manual_sourcer     sJ    ,B%%''--//J&T**?*?=@S@S@S*T*TTrU   
error_coderc   c                D    | dk    rt           S | dk    rt          S t          S )zHReturn cooldown seconds based on the HTTP status that caused exhaustion.  i  )EXHAUSTED_TTL_401_SECONDSEXHAUSTED_TTL_429_SECONDSEXHAUSTED_TTL_DEFAULT_SECONDS)r   s    r*   _exhausted_ttlr     s*    S((S((((rU   r   ra   c                   | | dk    rdS t          | t          t          f          r$t          |           }|dk    rdS |dk    r|dz  n|S t          | t                    r|                                 }|sdS 	 t          |          }n# t
          $ r d}Y nw xY w||dk    r|dz  n|S 	 t          j        |                    dd                    	                                S # t
          $ r Y dS w xY wdS )zBest-effort parse for provider reset timestamps.

    Accepts epoch seconds, epoch milliseconds, and ISO-8601 strings.
    Returns seconds since epoch.
    Nr   r   l    J)     @@Zz+00:00)
rP   rZ   floatrK   r   
ValueErrorr   fromisoformatr   	timestamp)r   numericraws      r*   r   r     s;    }t%#u&& L,,a<<4#*->#>#>wGK% kkmm 	4	CjjGG 	 	 	GGG	'.1B'B'B7V##O	)#++c8*D*DEEOOQQQ 	 	 	44	4s$   9B	 	BB+9C% %
C32C3messagec                x   | sd S t          j        d| t           j                  }|rTt          |                    d                    }|                    d                                          dk    r|dz  n|S t          j        d| t           j                  }|r"t          |                    d                    S t          j        d| t           j                  }|rKt          |                    d                    dz  t          |                    d                    d	z  z   S t          j        d
| t           j                  }|r%t          |                    d                    dz  S t          j        d| t           j                  }|r%t          |                    d                    d	z  S d S )Nz,quotaResetDelay[:\s\"]+(\d+(?:\.\d+)?)(ms|s)r      msr   z?retry\s+(?:after\s+)?(\d+(?:\.\d+)?)\s*(?:sec|secs|seconds|s\b)z'resets?\s+in\s+(\d+)\s*hr\s+(\d+)\s*minr<   <   zresets?\s+in\s+(\d+)\s*hr\bzresets?\s+in\s+(\d+)\s*min\b)research
IGNORECASEr   groupr   rZ   )r   delay_matchr   	sec_matchhr_min_matchhr_only_matchmin_only_matchs          r*   _extract_retry_delay_secondsr   2  s    t)KWVXVcddK Qk''**++!,!2!21!5!5!;!;!=!=!E!Euv~~5P	\^egigtuuI )Y__Q''(((9GRTR_``L S<%%a(())D03|7I7I!7L7L3M3MPR3RRRI<gr}UUM 2=&&q))**T11Y>WWN 1>''**++b004rU   error_contextOptional[Dict[str, Any]]rp   c                   t          | t                    si S i }|                     d          }t          |t                    r+|                                r|                                |d<   |                     d          }t          |t                    r+|                                r|                                |d<   |                     d          p)|                     d          p|                     d          }t          |          }|<t          |t                    r't          |          }|t          j                    |z   }|||d<   |S )Nreasonr   reset_at	resets_atretry_until)rP   dictr{   rK   r   r   r   time)r   r   r   r   r   parsed_reset_atretry_delay_secondss          r*   _normalize_error_contextr   I  sK   mT** 	!#Jx((F&# .6<<>> .%||~~
8	**G'3 0GMMOO 0 '
9*%% 	,[))	,]++ 
 099O:gs#;#;:7CC*"ikk,??O"!0
:rU   r   c                    | j         t          k    rd S t          t          | dd                     }||S | j        r| j        t          | j                  z   S d S )Nrg   )r`   STATUS_EXHAUSTEDr   r   rb   r   rd   )r   r   s     r*   _exhausted_untilr   b  se    ,,,t(8Mt)T)TUUH L#nU5J&K&KKK4rU   rw   c                v    |                                                                                      dd          S )z>Normalize a custom provider name for use as a pool key suffix. -)r   r   r   r   s    r*   _normalize_custom_pool_namer   m  s,    ::<<''S111rU   configc              #    K   | t                      } | dS |                     d          }t          |t                    s$	 ddlm}  ||           }n# t          $ r Y dS w xY w|sdS |D ]V}t          |t                    s|                    d          }t          |t                    sCt          |          |fV  WdS )zJYield (normalized_name, entry_dict) for each valid custom_providers entry.Ncustom_providersr   )get_compatible_custom_providersrw   )
r+   r{   rP   listr(   r  r)   r   rK   r   )r   r   r  r   rw   s        r*   _iter_custom_providersr  r  s     ~"$$~zz"455&-- 	IIIIII>>vFF 	 	 	FF	 ! 7 7%&& 	yy  $$$ 	)$//666667 7s   A 
A"!A"rh   r^   provider_namec                   | sdS |                                                      d          }|r6t          |          }t                      D ]\  }}||k    rt           | c S t                      D ]c\  }}t          |                    d          pd                                                               d          }|r||k    rt           | c S ddS )a~  Look up the custom_providers list in config.yaml and return 'custom:<name>' for a matching base_url.

    When provider_name is given, prefer matching by name first (solving the case where
    multiple custom providers share the same base_url but have different API keys).
    Falls back to base_url matching when no name match is found.

    Returns None if no match is found.
    N/rh   r   )r   rstripr   r  CUSTOM_POOL_PREFIXrK   r{   )rh   r  normalized_urlnormalized_name	norm_namer   	entry_urls          r*   get_custom_provider_pool_keyr    s	     t^^%%,,S11N
  :5mDD 6 8 8 	: 	:IuO++,9i99999 , 344 6 6	5		*--344::<<CCCHH	 	6n44(5)555554rU   	List[str]c                 X     t          d           t           fd D                       S )z?Return all 'custom:*' pool keys that have entries in auth.json.Nc              3     K   | ]P}|                     t                    t                              |          t                    D|         L|V  Qd S rs   )rQ   r  rP   r{   r  )r   r   	pool_datas     r*   r   z-list_custom_pool_providers.<locals>.<genexpr>  sx        >>,-- y}}S))400 cN	     rU   )r!   sorted)r  s   @r*   list_custom_pool_providersr    sH    $T**I          rU   pool_keyc                    |                      t                    sdS | t          t                    d         }t                      D ]\  }}||k    r|c S dS )zWReturn the custom_providers config entry matching a pool key like 'custom:together.ai'.N)rQ   r  lenr  )r  suffixr  r   s       r*   _get_custom_provider_configr    so    122 tc,--../F244  	5LLL 4rU   c                H   t                      }|t          S |                    d          }t          |t                    st          S t          |                    | d          pd                                                                          }|t          v r|S t          S )z8Return the configured selection strategy for a provider.Ncredential_pool_strategiesr   )	r+   STRATEGY_FILL_FIRSTr{   rP   r   rK   r   r   SUPPORTED_POOL_STRATEGIES)rJ   r   
strategiesstrategys       r*   get_pool_strategyr    s      F~""899Jj$'' #"":>>(B//5266<<>>DDFFH,,,rU   )rh   pool_or_providerc               J   t          | dd          }|t          | t                    r| }ndS t          |pd                                                                          }t          |pd                                                                          }|r|sdS ||k    rdS |dk    s|                    t                    sdS 	 t          |pd          }n# t          $ r Y dS w xY wt          |pd                                                                          |k    S )a  Return whether a pool belongs to the requested runtime provider.

    Named custom endpoints intentionally use two identities: the live agent is
    ``custom`` while its pool is keyed ``custom:<name>``. Accept that pair only
    when the runtime base URL resolves to the exact same custom pool key.
    Empty string identities fail closed. Legacy pool adapters without a
    ``provider`` attribute remain compatible; production pools are scoped.
    rJ   NTr   Fcustom)	r   rP   rK   r   r   rQ   r  r  r)   )r   rJ   rh   raw_pool_providerpool_providerprovider_normmatched_pools          r*    credential_pool_matches_providerr'    sF      0*dCC &,, 	 0
 4)/R006688>>@@MB''--//5577M  u%%t  (@(@AS(T(T u3HNCC   uu|!r""((**0022mCCs   	C 
C)(C)r   provider_idstateNonec                &   	 t          j                    }n# t          $ r Y dS w xY w|dS t          j                            d          rzt          j                            dd          }|rXt          |          dz  dz  }	 |                    d          |                    d          k    rdS n# t          $ r Y dS w xY w	 t          j        | ||d	           dS # t          $ r'}t          
                    d
| |           Y d}~dS d}~ww xY w)u  Persist a rotated OAuth ``state`` into the global-root auth.json.

    Best-effort write-through for the multi-profile rotation hazard
    (#48415 / #43589): nous, openai-codex, and xai-oauth rotate the
    refresh_token on refresh, so when a profile pool refresh rotates a grant
    it resolved from the root fallback, the rotated chain must land back in
    root. Otherwise root keeps a now-revoked refresh token and every other
    profile reading the stale root grant dies with ``refresh_token_reused`` /
    ``invalid_grant`` once its access token expires.

    Only updates ``providers.<provider_id>`` in the root store; never touches
    the profile store (the caller already saved that). Swallows all errors — a
    failed write-through degrades to the pre-existing behavior (root stale), it
    must never break the profile's own successful save. Mirrors
    ``hermes_cli.auth._write_through_xai_oauth_to_global_root`` (which covers
    the non-pool xAI refresh path) for the credential-pool refresh path.
    NPYTEST_CURRENT_TESTHOMEr   z.hermesz	auth.jsonF)strict
set_activez8%s pool refresh: write-through to global root failed: %s)r   _global_auth_file_pathr)   osenvironr{   r	   resolve _persist_provider_state_to_storeloggerdebug)r(  r)  global_pathreal_home_env	real_rootexcs         r*   ,_write_through_provider_state_to_global_rootr<    s   (577   
 
z~~+,, 
vr22 	]++i7+EI&&e&44	8I8IQV8I8W8WWWF X   
1		
 	
 	
 	
 	
 	
  
 
 
F	
 	
 	
 	
 	
 	
 	
 	
 	

s6    
$$.B3 3
C CC 
D)DDc                  <   e Zd ZdIdZdJdZdJd	ZdKd
ZdLdZdMdZdddNdZ	dOdZ
	 dPdQdZdRd ZdRd!ZdRd"ZdRd#ZdRd$ZdSd%ZdTd'ZdUd)ZdTd*ZdVd+ZdLd,Zd-d-d.dWd1Zd2d3dXd4ZdLd5Zddd6dYd9ZdPdZd;Zd[d<ZdLd=Z	 dPd\d>ZdLd?Zd]dAZ d^dCZ!d_dGZ"dRdHZ#dS )`CredentialPoolrJ   rK   r   r   c                    || _         t          |d           | _        d | _        t	          |          | _        t          j                    | _        i | _	        t          | _        d S )Nc                    | j         S rs   r   r   s    r*   <lambda>z)CredentialPool.__init__.<locals>.<lambda>3  s    %. rU   r   )rJ   r  _entries_current_idr  	_strategy	threadingLock_lock_active_leases%DEFAULT_MAX_CONCURRENT_PER_CREDENTIAL_max_concurrent)ru   rJ   r   s      r*   __init__zCredentialPool.__init__1  s]     w,H,HIII*.*844^%%
.0DrU   r#   r   c                *    t          | j                  S rs   )r   rD  rt   s    r*   has_credentialszCredentialPool.has_credentials:      DM"""rU   c                D    t          |                                           S )zCTrue if at least one entry is not currently in exhaustion cooldown.)r   _available_entriesrt   s    r*   has_availablezCredentialPool.has_available=  s    D++--...rU   c                *    t          | j                  S rs   )r  rD  rt   s    r*   r   zCredentialPool.entriesA  rP  rU   Optional[PooledCredential]c                X      j         sd S t           fd j        D             d           S )Nc              3  <   K   | ]}|j         j        k    |V  d S rs   )rX   rE  r   r   ru   s     r*   r   z)CredentialPool.current.<locals>.<genexpr>G  s2      VVuTEU9U9UU9U9U9U9UVVrU   )rE  nextrD  rt   s   `r*   currentzCredentialPool.currentD  s;     	4VVVVVVVX\]]]rU   oldrW   newr*  c                t    t          | j                  D ]"\  }}|j        |j        k    r|| j        |<    dS #dS )z4Swap an entry in-place by id, preserving sort order.N)	enumeraterD  rX   )ru   r[  r\  idxr   s        r*   _replace_entryzCredentialPool._replace_entryI  sP    #DM22 	 	JCx36!!%(c" "	 	rU   Nremoved_idsrb  Optional[List[str]]c               R    t          | j        d | j        D             |           d S )Nc                6    g | ]}|                                 S r   r   r   s     r*   
<listcomp>z+CredentialPool._persist.<locals>.<listcomp>S       888U]]__888rU   ra  )r"   rJ   rD  )ru   rb  s     r*   _persistzCredentialPool._persistP  s>    M88$-888#	
 	
 	
 	
 	
 	
rU   status_coderc   normalized_errorrp   c                    |dk    rdS |                     d          }t          |t                    sdS |                                                                t
          v S )uT  Detect upstream-permanent OAuth failures that won't recover on TTL.

        Only fires for 401 responses whose error code/reason matches a known
        terminal OAuth state (token_invalidated, token_revoked, invalid_grant,
        etc.).  Distinguishes permanent failures from transient ones like
        token_expired (refreshable) or generic 401 without a specific reason
        (could be a server-side glitch worth retrying).

        Returns False for non-401 status codes — 429 rate limits and 402
        billing failures are transient by nature and should keep TTL semantics.
        r   Fr   )r{   rP   rK   r   r   _TERMINAL_AUTH_REASONS)ru   rj  rk  r   s       r*   _is_terminal_auth_failurez(CredentialPool._is_terminal_auth_failureW  s^      #5!%%h//&#&& 	5||~~##%%)???rU   r   r   r   c                   t          |          }|                     ||          rt          }nt          }t	          ||t          j                    ||                    d          |                    d          |                    d                    }|                     ||           |                                  |S )Nr   r   r   r`   rb   rd   re   rf   rg   )	r   rn  STATUS_DEADr   r   r   r{   r`  ri  )ru   r   rj  r   rk  terminal_statusupdateds          r*   _mark_exhaustedzCredentialPool._mark_exhaustedn  s     4MBB ))+7GHH 	/)OO.O'9;;'.228<</33I>> 0 4 4Z @ @
 
 
 	E7+++rU   c                   | j         dk    s|j        dk    r|S 	 ddlm}  |            }|s|S |                    dd          }|                    dd          }|                    dd          }|j        pd}|j        pd}|s|r|r||k    s|r||k    rzt                              d	|j	                   t          ||p|j        |p|j        |p|j        d
d
d
d
d
d

  
        }	|                     ||	           |                                  |	S n2# t          $ r%}
t                              d|
           Y d
}
~
nd
}
~
ww xY w|S )a  Sync a claude_code pool entry from ~/.claude/.credentials.json if tokens differ.

        OAuth refresh tokens are single-use. When something external (e.g.
        Claude Code CLI, or another profile's pool) refreshes the token, it
        writes the new pair to ~/.claude/.credentials.json. The pool entry's
        refresh token becomes stale. This method detects that and syncs.
        rO   claude_coder   )read_claude_code_credentialsrefreshTokenr   accessToken	expiresAtzDPool entry %s: syncing tokens from credentials file (tokens changed)N)	r]   r_   rj   r`   rb   rd   re   rf   rg   z(Failed to sync from credentials file: %s)rJ   r\   agent.anthropic_adapterrw  r{   r]   r_   r6  r7  rX   r   rj   r`  ri  r)   )ru   r   rw  credsfile_refreshfile_accessfile_expiresentry_accessentry_refreshrs  r;  s              r*   +_sync_anthropic_entry_from_credentials_filez:CredentialPool._sync_anthropic_entry_from_credentials_file  s    =K''5<=+H+HL'	JLLLLLL0022E  99^R88L))M266K 99[!44L !-3L!/52M | !,!<!<  "=%1]%B%BZH   "!,!B0B"."E%2E"."E%2E $#'$(&*'+(,   ##E7333 	J 	J 	JLLCSIIIIIIII	Js   D C!D 
E D;;E c           	     ^   | j         dk    s|j        dk    r|S 	 t                      5  t                      }t	          |d          }ddd           n# 1 swxY w Y   t          |t                    s|S |                    d          }t          |t                    s|S |                    dd          }|                    dd          }|j        pd}|j	        pd}|r||k    s|r||k    rt                              d|j                   ||p|j	        ddddddd	}	|                    d
          r|d
         |	d
<   t          |fi |	}
|                     ||
           |                                  |
S n2# t           $ r%}t                              d|           Y d}~nd}~ww xY w|S )u  Sync a Codex device_code pool entry from auth.json if tokens differ.

        When a Codex OAuth access token expires (or the ChatGPT account hits
        its 5h/weekly quota), the pool entry gets marked ``STATUS_EXHAUSTED``
        with a ``last_error_reset_at`` that can be many hours in the future.
        Meanwhile the user may run ``hermes model`` / ``hermes auth`` which
        performs a fresh device-code login and writes new tokens to
        ``auth.json`` under ``_auth_store_lock``.  Without this sync the pool
        entry stays frozen until ``last_error_reset_at`` elapses — even
        though fresh credentials are sitting on disk — and every request
        fails with "no available entries (all exhausted or empty)".

        Mirrors the Nous/Anthropic resync paths above.  Only applies to
        device_code-sourced entries; env/API-key-sourced entries have no
        auth.json shadow to sync from.
        openai-codexdevice_codeNtokensr]   r   r_   zQPool entry %s: syncing Codex tokens from auth.json (refreshed by another process)r]   r_   r`   rb   rd   re   rf   rg   rk   z-Failed to sync Codex entry from auth.json: %srJ   r\   r   r   r   rP   r   r{   r]   r_   r6  r7  rX   r   r`  ri  r)   ru   r   
auth_storer)  r  store_accessstore_refreshr  r  field_updatesrs  r;  s               r*   !_sync_codex_entry_from_auth_storez0CredentialPool._sync_codex_entry_from_auth_store  s[   " =N**elm.K.KL*	O!## I I-//
,ZHHI I I I I I I I I I I I I I I eT** YYx((Ffd++ !::nb99L"JJ;;M !-3L!/52M ,,! -&3}&D&D5H   %1%2%Ie6I#'&*'+)-*.+/	1 	1 99^,, J49.4IM.1!%99=99##E7333 	O 	O 	OLLH#NNNNNNNN	OG   E; AE; AE; AE; 5+E; !CE; ;
F*F%%F*c           	     ^   | j         dk    s|j        dk    r|S 	 t                      5  t                      }t	          |d          }ddd           n# 1 swxY w Y   t          |t                    s|S |                    d          }t          |t                    s|S |                    dd          }|                    dd          }|j        pd}|j	        pd}|r||k    s|r||k    rt                              d|j                   ||p|j	        ddddddd	}	|                    d
          r|d
         |	d
<   t          |fi |	}
|                     ||
           |                                  |
S n2# t           $ r%}t                              d|           Y d}~nd}~ww xY w|S )a  Sync an xAI OAuth pool entry from auth.json if tokens differ.

        xAI OAuth refresh tokens are single-use.  When another Hermes process
        (or another profile sharing the same auth.json) refreshes the token,
        it writes the new pair to ``providers["xai-oauth"]["tokens"]`` under
        ``_auth_store_lock``.  Without this resync, our in-memory pool entry
        keeps the consumed refresh_token and the next ``_refresh_entry`` call
        would replay it and get a ``refresh_token_reused``-style 4xx.

        Only applies to entries seeded from the singleton (``device_code``);
        manually added entries are independent credentials with their own
        refresh-token lifecycle.
        	xai-oauthr  Nr  r]   r   r_   zUPool entry %s: syncing xAI OAuth tokens from auth.json (refreshed by another process)r  rk   z1Failed to sync xAI OAuth entry from auth.json: %sr  r  s               r*   %_sync_xai_oauth_entry_from_auth_storez4CredentialPool._sync_xai_oauth_entry_from_auth_store  sY    =K''5<=+H+HL'	S!## F F-//
,ZEEF F F F F F F F F F F F F F F eT** YYx((Ffd++ !::nb99L"JJ;;M -3L!/52M ,,! -&3}&D&D5H   %1%2%Ie6I#'&*'+)-*.+/	1 	1 99^,, J49.4IM.1!%99=99##E7333 	S 	S 	SLLLcRRRRRRRR	Sr  c                   | j         dk    rS 	 t          fdt          | j                   D             d          }t          |t                    sS t
                              | j         |          }|j        j        k    s|j        j        k    r8t          
                    dj                   |                     |           |S n2# t          $ r%}t          
                    d|           Y d}~nd}~ww xY wS )a  Adopt a token pair rotated by another pool instance.

        Direct xAI integrations load a fresh ``CredentialPool`` for each
        request. Their in-memory locks therefore cannot protect xAI's
        single-use refresh token across concurrent requests or processes.
        This helper is called while the shared auth-store lock is held and
        re-reads the exact persisted row before a refresh POST is attempted.
        r  c              3     K   | ]9}t          |t                    r"|                    d           j        k    5|V  :dS )rX   N)rP   r   r{   rX   )r   r   r   s     r*   r   zGCredentialPool._sync_xai_oauth_entry_from_pool_store.<locals>.<genexpr>J  s\        !'400 6=[[5F5F%(5R5R 5R5R5R5R rU   NzIPool entry %s: adopting xAI OAuth tokens rotated by another pool instancez7Failed to sync xAI OAuth entry from credential pool: %s)rJ   rY  r!   rP   r   rW   r   r]   r_   r6  r7  rX   r`  r)   )ru   r   	persistedstoredr;  s    `   r*   %_sync_xai_oauth_entry_from_pool_storez4CredentialPool._sync_xai_oauth_entry_from_pool_store;  sB    =K''L	Y   #7#F#F  
  I i.. %//yIIF#u'999'5+>>>_H   ##E6222 ?  	Y 	Y 	YLLRTWXXXXXXXX	Ys   AC A7C 
C=C88C=c                   | j         dk    sj        dk    rS 	 t                      5  t                      }t	          |d          }ddd           n# 1 swxY w Y   |sS |                    dd          }|                    dd          }|||                    d          |                    d          |                    d	          |                    d
          d}t          fd|                                D                       }|r't          	                    dj
                   ddddddd}|r||d<   |r||d<   |                    d          r|d         |d<   |                    d          r|d         |d<   |                    d	          r|d	         |d	<   |                    d
          r|d
         |d
<   t          j                  }	dD ]}
|                    |
          }|||	|
<   t          fd|	i|}|                     |           |                                  |S n2# t           $ r%}t          	                    d|           Y d}~nd}~ww xY wS )a  Sync a Nous pool entry from auth.json if tokens differ.

        Nous OAuth refresh tokens are single-use.  When another process
        (e.g. a concurrent cron) refreshes the token via
        ``resolve_nous_runtime_credentials``, it writes fresh tokens to
        auth.json under ``_auth_store_lock``.  The pool entry's tokens
        become stale.  This method detects that and adopts the newer pair,
        avoiding a "refresh token reuse" revocation on the Nous Portal.
        r   r  Nr_   r   r]   ri   rm   rn   rl   )r]   r_   ri   rm   rn   rl   c              3  P   K   | ] \  }}|d vot          |d          |k    V  !dS )Nr   N)r   )r   r   r   r   s      r*   r   zBCredentialPool._sync_nous_entry_from_auth_store.<locals>.<genexpr>~  sV        C Z'NGE3,E,E,N     rU   z0Pool entry %s: syncing Nous state from auth.jsonrp  rB   r@   rC   rH   rF   rI   rq   z,Failed to sync Nous entry from auth.json: %s)rJ   r\   r   r   r   r{   anyr   r6  r7  rX   r   rq   r   r`  ri  r)   )ru   r   r  r)  r  r  comparable_updatesshould_syncr  extra_updates	extra_keyvalrs  r;  s    `            r*    _sync_nous_entry_from_auth_storez/CredentialPool._sync_nous_entry_from_auth_storeb  s^    =F""elm&C&CL9	N!## A A-//
,Z@@A A A A A A A A A A A A A A A  !IIor::M 99^R88L ,!.#ii55"YY{33(-		2H(I(I&+ii0D&E&E" "     "4":":"<"<    K  #FH  
 $(&*'+)-*.+/1 1   A4@M.1  C5BM/299\** F272EM,/99[)) D16{1CM+.99344 Z<ABX<YM"8999122 V:?@T:UM"67 $U[ 1 1"; 7 7I  ))I..C36i0!%NN}NNN##E7333G#H  	N 	N 	NLLGMMMMMMMM	NsA   H< AH< AH< AH< #GH< <
I+I&&I+c                   |j         dk    rdS 	 t                      5  t                      }dddd                    | j                  }t          |          oVt          |                    d          t                    o-t          |d                             |          t                     }| j        dk    rt          |d          }|	 ddd           dS |j	        |d<   |j
        r
|j
        |d	<   |j        r
|j        |d
<   |j        r
|j        |d<   |j        r
|j        |d<   dD ]#}|j                            |          }||||<   $|j        r
|j        |d<   t!          |d|d           nz| j        dk    rt          |d          }t          |t                    s	 ddd           dS |                    d          }t          |t                    s	 ddd           dS |j	        |d<   |j
        r
|j
        |d	<   |j        r
|j        |d<   t!          |d|d           n| j        dk    rt          |d          }t          |t                    s	 ddd           dS |                    d          }t          |t                    s	 ddd           dS |j	        |d<   |j
        r
|j
        |d	<   |j        r
|j        |d<   t!          |d|d           n	 ddd           dS t%          |           |r|rt'          ||           ddd           dS # 1 swxY w Y   dS # t(          $ r,}	t*                              d| j        |	           Y d}	~	dS d}	~	ww xY w)ux  Write refreshed pool entry tokens back to auth.json providers.

        After a pool-level refresh, the pool entry has fresh tokens but
        auth.json's ``providers.<id>`` still holds the pre-refresh state.
        On the next ``load_pool()``, ``_seed_from_singletons()`` reads that
        stale state and can overwrite the fresh pool entry — potentially
        re-seeding a consumed single-use refresh token.

        Applies to any OAuth provider whose singleton lives in auth.json
        (currently Nous, OpenAI Codex, and xAI Grok OAuth).

        ``set_active=False`` on every write: a pool sync-back is a
        token-rotation side effect, not the user choosing a provider.
        Using ``_save_provider_state`` (which sets ``active_provider``)
        here would mean every Nous/Codex/xAI refresh in a multi-provider
        setup silently flips the ``active_provider`` flag — the next
        ``hermes`` invocation that defaults to the active provider
        (e.g. setup wizard, ``hermes auth status``) would land on
        whatever provider happened to refresh last, not whatever the
        user actually chose.
        r  Nr   r  r  )r   r  r  	providersr]   r_   ri   rm   rn   r  rl   Fr/  r  rk   z3Failed to sync %s pool entry back to auth store: %s)r\   r   r   r{   rJ   r   rP   r   r   r]   r_   ri   rm   rn   rq   rl   r    rk   r   r<  r)   r6  r7  )
ru   r   r  _wt_provider_idwrite_through_to_rootr)  r  r  r  r;  s
             r*   %_sync_device_code_entry_to_auth_storez4CredentialPool._sync_device_code_entry_to_auth_store  sZ   4 <=((FU	d!## R R-//
 #$2!,# # #dm$$	  
 )-_(=(= )z~~k::DAA "";/33ODDd C% =F**0VDDE}7R R R R R R R R8 -2,>E.)* E161Do.' ?.3.>l+ =-2_k*1 S8=8R45&? 3 3	 $kooi88?/2E),/ O6;6N23)*fePUVVVVV]n440^LLE%eT22 eR R R R R R R Rf #YYx00F%fd33 kR R R R R R R Rl .3-?F>** F272E/) C050Bn-)*neX]^^^^^]k110[IIE%eT22 AR R R R R R R RB #YYx00F%fd33 GR R R R R R R RH .3-?F>** F272E/) C050Bn-)*k5UZ[[[[[ YR R R R R R R R\ !,,,( _ @'  aR R R R R R R R R R R R R R R R R Rf  	d 	d 	dLLNPTP]_bccccccccc	ds   L, B1LL, CL&L, 3+LL, +A1LL, )+LL, !AL"L, /#LL, L##L, &L#'L, ,
M"6!MM"forcec                  |j         t          k    s|j        s|r|                     |d            d S | j        dv r| j        dk    r| j        n| j        }t          |                                           5   ||          }| j        dk    rN||ur'|}|s#| 	                    |          s|cd d d            S | 
                    ||          cd d d            S |j        |j        k    s|j        |j        k    r|cd d d            S | 
                    ||          cd d d            S # 1 swxY w Y   | 
                    ||          S )N)r  r  r  )timeout_secondsr  )rM   rR   r_   rt  rJ   r  r  r    _single_use_refresh_lock_timeout_entry_needs_refresh_refresh_entry_implr]   )ru   r   r  
sync_entrysynceds        r*   _refresh_entryzCredentialPool._refresh_entry  sQ   ?o--U5H- 2$$UD1114 =999 =N22 66? 
 " $ E E G G   E E $E**=N22U** &$ )T-F-Fu-M-M )#(E E E E E E E E  33E3GGE E E E E E E E '5+===+u/BBB!E E E E E E E E //e/DDE E E E E E E E E E E E E E E E  ''U';;;s$   65D,8D,!D,	D,,D03D0r   c                    | j         dk    rdnd}t          j        |d          }t          t	          t          j                  t	          |          dz             S )a0  Lock timeout for single-use-refresh-token providers.

        Covers the configured refresh POST timeout plus a margin so a slow
        token endpoint cannot make the flock give up before the refresh
        resolves.  Reads the provider's ``HERMES_*_REFRESH_TIMEOUT_SECONDS``
        override.
        r  $HERMES_CODEX_REFRESH_TIMEOUT_SECONDS"HERMES_XAI_REFRESH_TIMEOUT_SECONDS   g      @)rJ   r   	env_floatr   r   AUTH_LOCK_TIMEOUT_SECONDS)ru   env_varrefresh_timeout_secondss      r*   r  z/CredentialPool._single_use_refresh_lock_timeoutD  sg     }.. 325 	
 #+"4Wb"A"A(455)**S0
 
 	
rU   c          
        	 | j         dk    rddlm}  ||j        |j                            d                    }t          ||d         |d         |d         	          }|j        d
k    r[	 ddlm}  ||d         |d         |d                    nx# t          $ r&}t          
                    d|           Y d }~nMd }~ww xY wnC| j         dk    rm|                     |          }||ur|}t          j        |j        |j                  }t          ||d         |d         |                    d                    }n| j         dk    rm|                     |          }||ur|}t          j        |j        |j                  }t          ||d         |d         |                    d                    }nS| j         dk    rF|                     |          }||ur|}t          j        |           |                     |          }n|S 
ny# t          $ 
rk}	t          
                    d| j         |j        |	           | j         dk    r|j        d
k    r|                     |          }|j        |j        k    r4t          
                    d           	 ddlm}  ||j        |j                            d                    }t          ||d         |d         |d         t,          d d           }|                     ||           |                                  	 ddlm}  ||d         |d         |d                    n2# t          $ r%}t          
                    d|           Y d }~nd }~ww xY w|cY d }	~	S # t          $ r%}
t          
                    d|
           Y d }
~
n>d }
~
ww xY w|                     |          s!t          
                    d           |cY d }	~	S | j         dk    r|                     |          }|j        |j        k    rft          
                    d           t          |t,          d d d d d           }|                     ||           |                                  |cY d }	~	S t          j        |	          r>t          
                    d           	 t7                      5  t9                      }t;          |d          pi }t=          |t>                    r:|                    d          pi }t=          |t>                    rtA          |                    d          pd          !                                }tA          |j        pd          !                                }|r||k    r|"                    dd            |"                    dd            ||d<   dtG          |	dd          tA          |	          d d!tI          j%        tL          j'                  (                                d"|d#<   tS          |d|           tU          |           d d d            n# 1 swxY w Y   n2# t          $ r%}t          
                    d$|           Y d }~nd }~ww xY wd% | j+        D             }d& | j+        D             | _+        | j,        |j        k    rd | _,        |                     |'           Y d }	~	d S | j         dk    r|                     |          }|j        |j        k    rft          
                    d(           t          |t,          d d d d d           }|                     ||           |                                  |cY d }	~	S t          j-        |	          r>t          
                    d)           	 t7                      5  t9                      }t;          |d          pi }t=          |t>                    r:|                    d          pi }t=          |t>                    rtA          |                    d          pd          !                                }tA          |j        pd          !                                }|r||k    r|"                    dd            |"                    dd            ||d<   dtG          |	dd          tA          |	          d d!tI          j%        tL          j'                  (                                d"|d#<   tS          |d|           tU          |           d d d            n# 1 swxY w Y   n2# t          $ r%}t          
                    d*|           Y d }~nd }~ww xY wd+ | j+        D             }d, | j+        D             | _+        | j,        |j        k    rd | _,        |                     |'           Y d }	~	d S | j         dk    r|                     |          }|j        |j        k    r{t          
                    d-           t          |t,          d d d d d           }|                     ||           |                                  | .                    |           |cY d }	~	S t          j/        |	          rt          
                    d.           	 t7                      5  t9                      }t;          |d          p&|j0        |j1        |j2        |j3        |j4        |j5        d/}tA          |                    d          pd          !                                }tA          |j        pd          !                                }|r||k    rNt          j6        ||	d 0           t          j7        ||	d 0           tS          |d|           tU          |           d d d            n# 1 swxY w Y   n2# t          $ r%}t          
                    d1|           Y d }~nd }~ww xY wt          j8        d2t          j8         hfd3| j+        D             }fd4| j+        D             | _+        | j,        |j        k    rd | _,        |                     |'           Y d }	~	d S | 9                    |d            Y d }	~	d S d }	~	ww xY wt          |t,          d d d d d           }|                     ||           |                                  | .                    |           |S )5NrO   r   )refresh_anthropic_oauth_purehermes_pkce)use_jsonr]   r_   rj   )r]   r_   rj   rv  )_write_claude_code_credentialsz7Failed to write refreshed token to credentials file: %sr  rk   )r]   r_   rk   r  r   )force_refreshz'Credential refresh failed for %s/%s: %sz8Retrying refresh with synced token from credentials file)r]   r_   rj   r`   rb   rd   zDFailed to write refreshed token to credentials file (retry path): %szRetry refresh also failed: %sz7Credentials file has valid token, using without refreshuD   xAI OAuth refresh failed but auth.json has newer tokens — adoptingrp  zIxAI OAuth refresh token is terminally invalid; clearing local token stater  r   codeunknowncredential_pool_refresh_failureT)rJ   r  r   r   relogin_requiredatlast_auth_errorz,Failed to clear terminal xAI OAuth state: %sc                2    g | ]}|j         d k    |j        S r  r\   rX   r   items     r*   rg  z6CredentialPool._refresh_entry_impl.<locals>.<listcomp>
  1     # # #$(;-77 777rU   c                (    g | ]}|j         d k    |S r  r\   r  s     r*   rg  z6CredentialPool._refresh_entry_impl.<locals>.<listcomp>  /     % % %!%;-77 777rU   ra  uF   Codex OAuth refresh failed but auth.json has newer tokens — adoptingzKCodex OAuth refresh token is terminally invalid; clearing local token statez.Failed to clear terminal Codex OAuth state: %sc                2    g | ]}|j         d k    |j        S r  r  r  s     r*   rg  z6CredentialPool._refresh_entry_impl.<locals>.<listcomp>P  r  rU   c                (    g | ]}|j         d k    |S r  r  r  s     r*   rg  z6CredentialPool._refresh_entry_impl.<locals>.<listcomp>T  r  rU   u?   Nous refresh failed but auth.json has newer tokens — adoptingzDNous refresh token is terminally invalid; clearing local token state)r?   rE   rl   rA   r>   r=   )r   z-Failed to clear terminal Nous OAuth state: %szmanual:c                0    g | ]}|j         v |j        S r   r  r   r  singleton_sourcess     r*   rg  z6CredentialPool._refresh_entry_impl.<locals>.<listcomp>  s3     # # #$(;*;;; ;;;rU   c                &    g | ]}|j         v|S r   r  r  s     r*   rg  z6CredentialPool._refresh_entry_impl.<locals>.<listcomp>  s1     % % %!%;.??? ???rU   ):rJ   r{  r  r_   r\   endswithr   r  r)   r6  r7  r  r   refresh_codex_oauth_purer]   r{   r  refresh_xai_oauth_purer   resolve_nous_runtime_credentialsrX   r  	STATUS_OKr`  ri  r  $_is_terminal_xai_oauth_refresh_errorr   r   r   rP   r   rK   r   popr   r   nowr   utc	isoformatr   r   rD  rE  &_is_terminal_codex_oauth_refresh_errorr  _is_terminal_nous_refresh_errorr?   rE   rl   rA   r>   r=   _quarantine_nous_oauth_state_quarantine_nous_pool_entriesNOUS_DEVICE_CODE_SOURCErt  )ru   r   r  r  	refreshedrs  r  wexcr  r;  	retry_excr  r)  r  r  r  	clear_excrb  r  s                     @r*   r  z"CredentialPool._refresh_entry_implW  s   F	}++PPPPPP88'"\22=AA  	 "!*>!:"+O"<"+O"<	   <=00fZZZZZZ66%n5%o6%o6   
 % f f f%^`deeeeeeeef 1 .00
 ??FF&&"E$=&' 	 "!*>!:"+O"<!*~!>!>	   +-- CCEJJ&&"E$;&' 	 "!*>!:"+O"<!*~!>!>	   &((>>uEE&&"E9"'    ??FF |	 |	 |	LLBDMSXS[]`aaa }++0M0MII%PP'5+>>>LL![\\\QXXXXXX$@$@"0%+]%;%;M%J%J% % %	 #*")2>)B*3O*D*3O*D(1+/,0# # # ++FG<<<w^^^^^^:: ). 9 )/ : )/ :   
  ) w w w"LL)oquvvvvvvvvw&$ Q Q Q%DiPPPPPPPPQ226:: "LL!Z[[[!MMMMMM }++CCEJJ'5+>>>LL^   &$-'+(,*.+/,0  G ''888MMOOO"NNNNNN @EE * LLc  -// E E)9););J$8[$Q$Q$WUWE)%66 E).8)<)<)B#-fd#;#; !E47

?8S8S8YWY4Z4Z4`4`4b4bM478K8Qr4R4R4X4X4Z4ZM+8 %EM]<Z<Z(.

>4(H(H(H(.

?D(I(I(I:@h8C4;C4S4S7:3xx6W@D2:,x|2L2L2V2V2X2XD* D*.?(@ )=ZV[(\(\(\(8(D(D(D+E E E E E E E E E E E E E E E, %   JI       # #,0M# # #K% %)-% % %DM '5833+/(MMkM:::44444
 }..??FF'5+>>>LL`   &$-'+(,*.+/,0  G ''888MMOOO"NNNNNN B3GG * LLe  -// E E)9););J$8^$T$T$ZXZE)%66 E).8)<)<)B#-fd#;#; !E47

?8S8S8YWY4Z4Z4`4`4b4bM478K8Qr4R4R4X4X4Z4ZM+8 %EM]<Z<Z(.

>4(H(H(H(.

?D(I(I(I:@h8F4;C4S4S7:3xx6W@D2:,x|2L2L2V2V2X2XD* D*.?(@ )=ZY^(_(_(_(8(D(D(D+E E E E E E E E E E E E E E E, %   Li       # #,0M# # #K% %)-% % %DM '5833+/(MMkM:::44444 }&&>>uEE'5+>>>LL!bccc%$-'+(,*.+/,0  G ''888MMOOO>>wGGG"NNNNNN;C@@ . LL!ghhha-// = =)9););J$8V$L$L %-2_383H6;6N.3.>).',yQ QE -0		/0J0J0Pb,Q,Q,W,W,Y,YM,/0C0Ir,J,J,P,P,R,RM#0 =M]4R4R ( E$)$'+L!" !" !" !"
 !) F$.$'+L!" !" !" !"
 !5Z O O O 0 < < <1= = = = = = = = = = = = = = =2 % a a a%TV_````````a !8D("BDD)%# # # #,0M# # #K% % % %)-% % %DM '5833+/(MMkM:::44444  ---44444y|	| ! "# $
 
 
 	E7+++ 	227;;;s  A+H /%B H 
C C;H CEH rA?rBN#%M	N	
M8M3.N3M88N<r
N1N,'r,N113r$r*Br;r/r1Y?E1X<0Y<Y 	 YY 	Yr
Y7Y2-r2Y77ArBr%r+/rd2)E1d&d2&d*	*d2-d*	.d21r2
e!<ere!!Ar>B&r$r*/rn:(C:n."n:.n2	2n:5n2	6n:9r:
o)o$r$o))A6r%rrc                   |j         t          k    rdS | j        dk    rE|j        dS t	          |j                  t	          t          j                    dz            dz   k    S | j        dk    rt          |j        t                    S | j        dk    r1t          j
        |j        t          j        |j                            S | j        dk    rdS dS )NFrO     i r  r  r   )rM   rR   rJ   rj   rZ   r   r   r]   r   r   _xai_access_token_is_expiring#_xai_proactive_refresh_skew_secondsru   r   s     r*   r  z#CredentialPool._entry_needs_refresh  s    ?o--5=K''"*uu*++s49;;3E/F/F/PPP=N**2"7   =K''9"<U=OPP   =F"" 5urU   c                l    | j         5  |                                 cd d d            S # 1 swxY w Y   d S rs   )rI  _select_unlockedrt   s    r*   selectzCredentialPool.select  s}    Z 	+ 	+((**	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+   )--Fclear_expiredrefreshr  r  c          
        t          j                     }d}g }g }| j        D ]}|j        t          k    r|j        s| j        dk    r=|j        dk    r2|j        t          t          hv r| 
                    |          }||ur|}d}| j        dk    r=|j        dk    r2|j        t          t          hv r|                     |          }||ur|}d}| j        dk    r=|j        dk    r2|j        t          t          hv r|                     |          }||ur|}d}| j        dk    r=|j        dk    r2|j        t          t          hv r|                     |          }||ur|}d}|j        t          k    rt          |j                  r{|j        pd	}	|	rp||	z
  t           k    rb|j        p|j        d
d         }
t&                              d|
|j        pd||	z
  dz  | j                   |                    |j                   d}|j        t          k    rPt/          |          }|||k     r|r5t1          |t2          d
d
d
d
d
          }|                     ||           |}d}|r2|                     |          r|                     |d          }|n|}|                    |           |r't;          |          fd| j        D             | _        |r|                     |           |S )a  Return entries not currently in exhaustion cooldown.

        When *clear_expired* is True, entries whose cooldown has elapsed are
        reset to STATUS_OK and persisted.  When *refresh* is True, entries
        that need a token refresh are refreshed (skipped on failure).
        FrO   rv  Tr   r  r  r  r   N   uh   credential pool: pruning DEAD manual entry %s (reason=%s, age=%.1fh) — re-add via `hermes auth add %s`r  g      @rp  r  c                &    g | ]}|j         v|S r   rX   )r   e
pruned_idss     r*   rg  z5CredentialPool._available_entries.<locals>.<listcomp>B  s%    PPP1Z9O9OQ9O9O9OrU   ra  )r   rD  rM   rS   r   rJ   r\   r`   r   rq  r  r  r  r  r   rb   DEAD_MANUAL_PRUNE_TTL_SECONDSrY   rX   r6  warningre   appendr   r   r  r`  r  r  setri  )ru   r  r  r  cleared_anyentries_to_prune	availabler   r  dead_at_labelexhausted_untilclearedr  r  s                 @r*   rR  z!CredentialPool._available_entries  s    ikk&(,.	] e	$ e	$E "333E<Q3 ,,1N1N).>-LLLII%PP&&"E"&K
 ''55).>-LLL>>uEE&&"E"&K //55).>-LLL??FF&&"E"&K
 ,,55).>-LLLCCEJJ&&"E"&K K// %U\22 +#27aG +3=3P#P#P!&!<!Y"!3@y 7]f4 M   )//999&*  $444"25"9"9".33H3H  '%$-'+(,*.+/,0  G ''w777#E"&K "444U;; " //U/CC	$!U#### 	Q-..JPPPPPPPDM 	8MM&6M777rU   Tr  c                  |                      d|          }|s#d | _        t                              d           d S | j        t
          k    r"t          j        |          j        | _        S | j        t          k    rbt          |          dk    rOt          |d           t          j        dz             }|                     |           j        | _        |S | j        t          k    rt          |          dk    r|d         fd	| j        D             }|                    t          t          | j                  dz
  
                     d t%          |          D             | _        |                                  j        | _        |                                 pS |d         j        | _        S )NTr  z>credential pool: no available entries (all exhausted or empty)r   c                    | j         S rs   ro   )r  s    r*   rB  z1CredentialPool._select_unlocked.<locals>.<lambda>T  s     rU   rC  r  r   c                4    g | ]}|j         j         k    |S r   r  )r   	candidater   s     r*   rg  z3CredentialPool._select_unlocked.<locals>.<listcomp>]  s)    \\\Y9<SXS[C[C[yC[C[C[rU   r   c                6    g | ]\  }}t          ||           S r   r   )r   r_  r
  s      r*   rg  z3CredentialPool._select_unlocked.<locals>.<listcomp>_  s)    ggg.#yWY===gggrU   )rR  rE  r6  inforF  STRATEGY_RANDOMr:   choicerX   STRATEGY_LEAST_USEDr  minr   ro   r`  STRATEGY_ROUND_ROBINrD  r  r^  ri  rZ  )ru   r  r   rs  rotatedr   s        @r*   r  zCredentialPool._select_unlockedG  s   ++$+PP	 	#DKKXYYY4>_,,M),,E$xDL>000S^^a5G5G	'@'@AAAEe53F3JKKKGw///$xDN>111c)nnq6H6HaLE\\\\$-\\\GNN753t}3E3E3IJJJKKKggT]^eTfTfgggDMMMOOO$xD<<>>*U*! 8rU   c                r    |                                  }||S |                                 }|r|d         nd S Nr   )rZ  rR  )ru   rZ  r   s      r*   peekzCredentialPool.peekh  s>    ,,..N++--	(2y||d2rU   )r   api_key_hintr  r^   c                  | j         5  d r!t          fd| j        D             d           (|                                 p|                                 	 d d d            d S j        pj        d d         }|                     ||           t          fd| j        D                       }|j        t          k    r%t                              d|||j        pd           nt                              d||           d | _        |                                 }|r1|j        p|j        d d         }t                              d|           |cd d d            S # 1 swxY w Y   d S )Nc              3  2   K   | ]}|j         k    |V  d S rs   r   )r   r  r  s     r*   r   z;CredentialPool.mark_exhausted_and_rotate.<locals>.<genexpr>~  s0      SS11Bl1R1RQ1R1R1R1RSSrU   r  c              3  <   K   | ]}|j         j         k    |V  d S rs   r  )r   r  r   s     r*   r   z;CredentialPool.mark_exhausted_and_rotate.<locals>.<genexpr>  s1      >>qQTUX-=-=-=-=-=-=>>rU   ux   credential pool: marking %s DEAD (status=%s, reason=%s) — permanently failed, will NOT re-enter rotation until re-authr  z;credential pool: marking %s exhausted (status=%s), rotatingzcredential pool: rotated to %s)rI  rY  rD  rZ  r  rY   rX   rt  r`   rq  r6  r  re   r  rE  )	ru   rj  r   r  r  updated_entry
next_entry_next_labelr   s	      `    @r*   mark_exhausted_and_rotatez(CredentialPool.mark_exhausted_and_rotateo  s    Z %	 %	E 
 SSSSSSS  }A$*?*?*A*A}%	 %	 %	 %	 %	 %	 %	 %	 [0EHRaRLF  ]CCC >>>>DM>>> M (K77SK)H)UI    QK    $D..00J K(.C*-2C<kJJJK%	 %	 %	 %	 %	 %	 %	 %	 %	 %	 %	 %	 %	 %	 %	 %	 %	 %	s   AE%*C.E%%E),E)credential_idc                     j         5  |r; j                            |d          dz    j        |<   | _        |cddd           S                      dd          }|s	 ddd           dS  fd|D             }|r|n|}t          | fd          } j                            |j        d          dz    j        |j        <   |j         _        |j        cddd           S # 1 swxY w Y   dS )	a\  Acquire a soft lease on a credential.

        If a specific credential_id is provided, lease that entry directly.
        Otherwise prefer the least-leased available credential, using priority as
        a stable tie-breaker. When every credential is already at the soft cap,
        still return the least-leased one instead of blocking.
        r   r   NTr  c                f    g | ]-}j                             |j        d           j        k     +|.S )r   )rJ  r{   rX   rL  rX  s     r*   rg  z0CredentialPool.acquire_lease.<locals>.<listcomp>  sF       &**58Q77$:NNN NNNrU   c                R    j                             | j        d          | j        fS r  )rJ  r{   rX   r[   )r   ru   s    r*   rB  z.CredentialPool.acquire_lease.<locals>.<lambda>  s#    4#6#:#:58Q#G#G"X rU   rC  )rI  rJ  r{   rE  rR  r  rX   )ru   r!  r   	below_cap
candidateschosens   `     r*   acquire_leasezCredentialPool.acquire_lease  s    Z 	 	 %595H5L5L]\]5^5^ab5b#M2#0 $		 	 	 	 	 	 	 	 //dD/QQI 	 	 	 	 	 	 	 	   #,  I '0>YJXXXX  F .2-@-D-DVYPQ-R-RUV-VD	*%yD9+	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   1C%C%.A*C%%C),C)c                    | j         5  | j                            |d          }|dk    r| j                            |d           n|dz
  | j        |<   ddd           dS # 1 swxY w Y   dS )z/Release a previously acquired credential lease.r   r   N)rI  rJ  r{   r  )ru   r!  counts      r*   release_leasezCredentialPool.release_lease  s    Z 	? 	?'++M1==Ezz#''t<<<<5:QY#M2	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	? 	?s   AA  A$'A$c                l    | j         5  |                                 cd d d            S # 1 swxY w Y   d S rs   )rI  _try_refresh_current_unlockedrt   s    r*   try_refresh_currentz"CredentialPool.try_refresh_current  s}    Z 	8 	85577	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8r  c                F   | j         5  d}r"t          fd| j        D             d          }n*|                                 p|                     d          }|	 ddd           dS |j        | _        |                                 cddd           S # 1 swxY w Y   dS )a  Force-refresh the entry that supplied ``api_key_hint``.

        Direct provider integrations may reload the pool after a request has
        already failed, so they cannot rely on ``current_id`` identifying the
        issuing credential. With no hint, select an entry without first doing
        the normal proactive refresh; the forced refresh below must consume a
        rotating refresh token exactly once.
        Nc              3  2   K   | ]}|j         k    |V  d S rs   r  )r   r
  r  s     r*   r   z6CredentialPool.try_refresh_matching.<locals>.<genexpr>  s=        %$4DD "DDDD rU   Fr  )rI  rY  rD  rZ  r  rX   rE  r-  )ru   r  r   s    ` r*   try_refresh_matchingz#CredentialPool.try_refresh_matching  s-    Z 	8 	8E 
O   )-  
   N$*?*?*?*N*N}	8 	8 	8 	8 	8 	8 	8 	8  %xD5577!	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8s   AB*BBBc                    |                                  }|d S |                     |d          }||j        | _        |S )NTr  )rZ  r  rX   rE  )ru   r   r  s      r*   r-  z,CredentialPool._try_refresh_current_unlocked  sG    =4''T'::	 (|DrU   rZ   c                   d}g }| j         D ][}|j        s|j        s|j        r/|                    t          |d d d d d d                      |dz  }F|                    |           \|r|| _         |                                  |S )Nr   rp  r   )rD  r`   rb   rd   r  r   ri  )ru   r*  new_entriesr   s       r*   reset_statuseszCredentialPool.reset_statuses  s    ] 	* 	*E  *E$8 *E<Q *""$('+(,*.+/,0  
 
 
 
""5)))) 	'DMMMOOOrU   indexc                L   |dk     s|t          | j                  k    rd S | j                            |dz
            }d t          | j                  D             | _        t	          | j        d | j        D             |j        g           | j        |j        k    rd | _        |S )Nr   c                6    g | ]\  }}t          ||           S r  r  )r   new_priorityr   s      r*   rg  z/CredentialPool.remove_index.<locals>.<listcomp>  s9     
 
 
#e EL111
 
 
rU   c                6    g | ]}|                                 S r   rf  r   s     r*   rg  z/CredentialPool.remove_index.<locals>.<listcomp>  rh  rU   ra  )r  rD  r  r^  r"   rJ   rX   rE  )ru   r6  removeds      r*   remove_indexzCredentialPool.remove_index  s    199DM 2 2224-##EAI..
 
'0'?'?
 
 
 	M88$-888 	
 	
 	
 	

 wz))#DrU   targetr
   ?Tuple[Optional[int], Optional[PooledCredential], Optional[str]]c                ^   t          |pd                                          sdS t          | j        d          D ]\  }}|j        k    r||d fc S fdt          | j        d          D             }t          |          dk    r|d         d         |d         d         d fS t          |          dk    r	d d d dfS                                 rMt                    }d|cxk    rt          | j                  k    rn n|| j        |dz
           d fS d d d	| d
fS d d d dfS )Nr   )NNzNo credential target provided.r   )startc                    g | ]J\  }}|j                                                                                                         k    F||fKS r   )rY   r   r   )r   r_  r   r   s      r*   rg  z1CredentialPool.resolve_target.<locals>.<listcomp>!  sX     
 
 
U{  ""((**ciikk99 %L999rU   r   zAmbiguous credential label "z-". Use the numeric index or entry id instead.zNo credential #.zNo credential matching "z".)rK   r   r^  rD  rX   r  isdigitrZ   )ru   r=  r_  r   label_matchesr6  r   s         @r*   resolve_targetzCredentialPool.resolve_target  s   &,B%%'' 	@??#DM;;; 	( 	(JCx3E4'''' 
 
 
 
'Q???
 
 

 }"" #A&a(8(;TAA}!!pcppppp;;== 	:HHEE////S///////dmEAI6<<999999T=c=====rU   c                    t          |t          | j                            }| j                            |           |                                  |S )Nr   )r   r   rD  r  ri  r  s     r*   	add_entryzCredentialPool.add_entry1  sF    t}(E(EFFFU###rU   )rJ   rK   r   r   )r#   r   )r#   r   )r#   rU  )r[  rW   r\  rW   r#   r*  )rb  rc  r#   r*  )rj  rc   rk  rp   r#   r   rs   )r   rW   rj  rc   r   r   r#   rW   )r   rW   r#   rW   )r   rW   r#   r*  )r   rW   r  r   r#   rU  )r#   r   r   rW   r#   r   )r  r   r  r   r#   r   )r  r   r#   rU  )rj  rc   r   r   r  r^   r#   rU  )r!  r^   r#   r^   )r!  rK   r#   r*  )r  r^   r#   rU  )r#   rZ   )r6  rZ   r#   rU  )r=  r
   r#   r>  )$r~   r   r   rM  rO  rS  r   rZ  r`  ri  rn  rt  r  r  r  r  r  r  r  r  r  r  r  rR  r  r  r   r(  r+  r.  r1  r-  r5  r<  rE  rG  r   rU   r*   r>  r>  0  s2       E E E E# # # #/ / / /# # # #^ ^ ^ ^
    >B 
 
 
 
 
 
@ @ @ @6 37	    >2 2 2 2h> > > >@8 8 8 8t% % % %NF F F FPqd qd qd qdf%< %< %< %<N
 
 
 
&Z Z Z Zx
   0+ + + + ;@QV v v v v v vp 37      B3 3 3 3 37&*, , , , , ,\    >? ? ? ?8 8 8 8
 -18 8 8 8 8:      0   "> > > >2     rU   r>  r   c                |   g }t          |           D ]%\  }}|j        |k    r|                    |           &|r|d         nd }t          |dd                    r fdt          |           D             | d d <   ||                    dt          j                    j        d d                    |                    dt          |                      |                    d|	                    d          p|           |                     t                              ||                     dS | |         }i }	i }
d	 t          |          D             }|                                D ]d\  }}|d
v s||dk    r|j        r||v rt          ||          |k    r||	|<   8|t           v r#|j        	                    |          |k    r||
|<   e|	s|
r[|
ri |j        |
|	d<   t%          |fi |	}|| |<   t'                    p)|                                |                                k    S t'                    S )Nr   r   c                "    g | ]\  }}|v	|S r   r   )r   r_  r   duplicate_indicess      r*   rg  z!_upsert_entry.<locals>.<listcomp>A  s(    aaa
UCO`D`D`eD`D`D`rU   rX   r   r[   rY   Tc                    h | ]	}|j         
S r   r   r   s     r*   r   z _upsert_entry.<locals>.<setcomp>M  s    555qAF555rU   >   rX   r[   rq   )r^  r\   r  r  r   r   r   r   r   r{   rW   r   r   r   rY   r   rz   rq   r   r   r   )r   rJ   r\   r   matching_indicesr_  r   existing_idxexistingr  r  _field_namesr   r   rs  rK  s                  @r*   _upsert_entryrQ  8  s   (( ) )
U<6!!##C(((*:D#A&&L,QRR011 baaaai.@.@aaa
4!1"1"!5666:~g'>'>???7GKK$8$8$BFCCC'11(GDDEEEt|$HMM55F8$4$4555Lmmoo 
+ 
+
U$$$'>>hn>,x%%..%*c"K~!!#&&%//%*c" R R 	I%H%H-%HM'"(44m44 ' %&&Q(*:*:*<*<@Q@Q*QQ!"""rU   c                `  	 | dk    rdS dddddd	t          d	 |D             d
           }t          d |D             	fd          }g ||}d t          |          D             }d}t          |          D ]1\  }}|j        |k    r!t          ||          |||j                 <   d}2|S )NrO   Fr   r   r         )zenv:ANTHROPIC_TOKENzenv:CLAUDE_CODE_OAUTH_TOKENr  rv  zenv:ANTHROPIC_API_KEYc              3  B   K   | ]}t          |j                  |V  d S rs   r   r\   r   s     r*   r   z-_normalize_pool_priorities.<locals>.<genexpr>q  s2      GG5'8'F'FGGGGGGGrU   c                    | j         S rs   r   rA  s    r*   rB  z,_normalize_pool_priorities.<locals>.<lambda>r  s    %. rU   rC  c              3  B   K   | ]}t          |j                  |V  d S rs   rV  r   s     r*   r   z-_normalize_pool_priorities.<locals>.<genexpr>u  s2      KK5+<U\+J+JKKKKKKKrU   c                n                         | j        t                              | j        | j        fS rs   )r{   r\   r  r[   rY   )r   source_ranks    r*   rB  z,_normalize_pool_priorities.<locals>.<lambda>v  s/    OOEL#k*:*:;;NK
 rU   c                $    i | ]\  }}|j         |S r   r  )r   r_  r   s      r*   r   z._normalize_pool_priorities.<locals>.<dictcomp>~  s     DDD:33DDDrU   r   T)r  r^  r[   r   rX   )
rJ   r   manual_entriesseeded_entriesordered	id_to_idxchangedr9  r   rZ  s
            @r*   _normalize_pool_prioritiesra  e  s   ;u  !'(!" K GGGGGG((  N KKGKKK
 
 
 
  N 100GDD71C1CDDDIG(11  e>\))+25<+P+P+PGIeh'(GNrU   Tuple[bool, Set[str]]c                  % d}t                      }t                      }	 ddlm} n# t          $ r d }Y nw xY w| dk    r	 ddlm}  |d          s||fS n# t          $ r Y nw xY wt                      %dP%fd
} |d          } |d          p
 |d          }	t          |o|	           }
|
r9d |D             }t          |          t          |          k    r	||d d <   d}||fS ddl	m
}m} d |            fd |            ffD ]\  }}|r|                    d          r || |          r)|                    |           |t          || ||t          |                    dd          |                    d          |                    d          t!          |                    dd          |          d          z  }	n| dk    rt#          |d          }t          t%          |t&                    okt)          |                    d          pd                                          p5t)          |                    d          pd                                                    }|r7|s5d |D             }t          |          t          |          k    r	||d d <   d}|rB|r? || d          s2|                    d           t)          |                    d          pd                                          }|p#t!          |                    dd          d          }|t          || di dddt          d|                    dd          d |                    d           d!|                    d!          d"|                    d"          d#|                    d#          d$|                    d$          d%|                    d%          d&|                    d&          d|                    d          d'|                    d'          d(|                    d(          d)|                    d)          d*|                    d*          d+|                    d+          d,|                    d,          |                    d-          t%          |                    d.          t&                    r|                    d.          nd |d/          z  }n| d0k    r	 dd1lm}m}  |            \  }}|r ||          \  }}d2|                                v rd3nd4| } || |          sV|                    |           t5          j        |           }|p
|r|j        nd}|t          || ||t8          |||d5          z  }n1# t:          $ r&}t<                              d6|           Y d }~nd }~ww xY w| d7k    r	 dd8lm }  |d9          }|                    d:d          }|r|                    dd;          } || |          sq|                    |           |t          || ||t          ||                    d<          |                    d=d          |                    d>|          d?          z  }n8# t:          $ r&}t<                              d@|           Y d }~nd }~ww xY w| dAk    r	 ddBlm!}  |dA          }|rP|                    d          r:dC} || |          s+|                    |           d }	 ddDl"m"}  |                    d!d          }!|!r7tG          | $                    |!          %                                dEz            }n# t:          $ r d }Y nw xY wt)          |                    d&d          pd          &                    dF          }"|t          || ||t          |d         |                    d           ||"|                    dd          p#t!          |                    dd          |          dG          z  }n# t:          $ r&}t<                              dH|           Y d }~nld }~ww xY w| dIk    rC || d          r||fS t#          |dI          }t%          |t&                    r|                    dJ          nd }#t%          |#t&                    r|#                    d          r|                    d           t)          |                    d          pd                                          }|t          || ddt          |#                    dd          |#                    d           dK|                    dL          |p#t!          |#                    dd          d          dM          z  }n| dNk    rt#          |dN          }t%          |t&                    r|                    dJ          nd }#t%          |#t&                    r|#                    d          rd} || |          r||fS |                    |           ddOlm'}$ |$}"|t          || ||t          |#                    dd          |#                    d           |"|                    dL          t!          |#                    dd          |          dM          z  }||fS )QNFr   is_source_suppressedc                    dS NFr   _p_ss     r*   _is_suppressedz-_seed_from_singletons.<locals>._is_suppressed      5rU   rO   )!is_provider_explicitly_configuredr   rK   r#   c                v                         |           pt          | d          pd                                S r  )r{   _get_secretr   )r   	_env_files    r*   _env_valz'_seed_from_singletons.<locals>._env_val  s5    MM#&&D+c2*>*>D"KKMMMrU   ANTHROPIC_API_KEYANTHROPIC_TOKENCLAUDE_CODE_OAUTH_TOKENc                $    g | ]}|j         d v|S )>   rv  r  r  r   s     r*   rg  z)_seed_from_singletons.<locals>.<listcomp>  s0       <'EEE EEErU   T)rw  read_hermes_oauth_credentialsr  rv  ry  r   rx  rz  )r\   rM   r]   r_   rj   rY   r   r]   rm   c                $    g | ]}|j         d v|S )>   manual:device_coder  r  r   s     r*   rg  z)_seed_from_singletons.<locals>.<listcomp>  s0       <'LLL LLLrU   r  rY   r\   rM   r_   ri   rA   r>   r?   rE   rl   rn   rB   r@   rC   rH   rF   rI   r=   )rI   r=   rY   copilot)resolve_copilot_tokenget_copilot_api_tokenghgh_clienv:r\   rM   r]   rh   rY   zCopilot token seed failed: %sz
qwen-oauth) resolve_qwen_runtime_credentials)refresh_if_expiringr6   zqwen-clirj   rh   	auth_file)r\   rM   r]   rj   rh   rY   z Qwen OAuth token seed failed: %szminimax-oauth)get_provider_auth_stater5   )r   r  r  )r\   rM   r]   r_   rj   rh   rY   z#MiniMax OAuth token seed failed: %sr  r  z%https://chatgpt.com/backend-api/codexrk   )r\   rM   r]   r_   rh   rk   rY   r  )DEFAULT_XAI_OAUTH_BASE_URLr   rK   r#   rK   )(r  r   hermes_cli.authre  ImportErrorrm  r   r   r  r{  rw  rv  r{   addrQ  rR   r   r   rP   r   rK   r   hermes_cli.copilot_authrz  r{  r   r   rl   rS   r)   r6  r7  r  r  r   rZ   r   r   r  r  )&rJ   r   r`  active_sourcesr  rk  rm  rq  anthropic_api_keyanthropic_oauth_envapi_key_path_explicitretainedrw  rv  source_namer|  r)  has_runtime_materialcustom_labelseeded_labelrz  r{  rL   r\   	api_tokenenterprise_base_urlpconfigeffective_base_urlr;  r  r  rj   _dtr   rh   r  r  rp  s&                                        @r*   _seed_from_singletonsr    sb   G"uuN!##JJJJJJJJ   	 	 	 	 	 ;
	IIIIII44[AA /../ 	 	 	D	& JJ		N 	N 	N 	N 	N 	N %H%899H&''N884M+N+N 	 !%%6%R?R;R S S  	+ #*  H 8}}G,,%
N**gggggggg 99;;<88::;#
 	 	K  =11 !>(K88 "";///="-%4(-		-(D(D).>)B)B).;)?)?!1%))M22N2NP[!\!\ 	  	, 
V		$Z88#ud## EIIn--344::<< =uyy--344::<<	 
  
  	- 	 #*  H 8}}G,,%
 *	) *	..=2Y2Y *	}---
 uyy117R88>>@@L' +;		."--}, ,L }m #EIInb$A$A $UYY%?%?	
 !%))L"9"9 !%))L"9"9 UYYw//  ;!7!7 &uyy1B'C'C )%))4H*I*I  ;!7!7 +EII6L,M,M& "599]#;#;'( !%))L"9"9)* #EIIn$=$=+, +EII6L,M,M-. '		2D(E(E/0 .3YY7N-O-O/9%))E:J:JD/Q/Q[599U+++W[)5  	     GD 
Y			?\\\\\\\\1133ME6 1F1Fu1M1M.	.*.&,,..*@*@hhoVoo%~h<< "&&{333/3H==G *= *6=E222 ' } #&1):,5(:%+ 	    G  	? 	? 	?LL8#>>>>>>>>	? 
\	!	!	BHHHHHH44OOOEIIi,,E #ii*==%~h<< "&&{333} #&1)8,1-2YY-G-G(-		*b(A(A%*YY{K%H%H 	    G  	B 	B 	BLL;SAAAAAAAA	B 
_	$	$!	E??????++O<<E >22 %%~h<< "&&{333$(M-<<<<<<#iib99 [,/0A0A#0F0F0P0P0R0RUY0Y,Z,ZM$ - - -(,-"599-A2#F#F#L"MMTTUXYYH} #&1)8,1.,A-2YY-G-G-:(0%*YYw%;%; &?O %		." = ={@ @
 
	    G   	E 	E 	ELL>DDDDDDDD	E 
^	#	#
 >(M22 	+N**$Z@@(25$(?(?I8$$$T fd## 	

>(B(B 	}---uyy117R88>>@@L}+!0$*JJ~r$B$B%+ZZ%@%@ G$)IIn$=$=)l-=fjjY[>\>\^k-l-l 	  G 
[	 	  %Z==(25$(?(?I8$$$Tfd## 	

>(B(B 	 #F~h// /..v&&&BBBBBB1H}$!0$*JJ~r$B$B%+ZZ%@%@ ($)IIn$=$=-fjj.L.LfUU 	  G N""s   ( 88A 
A&%A&5B$V 
W%WWB=Z 
[Z??[A`5  A]6 5`5 6^`5 ^B.`5 5
a%?a  a%c                |   d}t                      }dd}	 ddlm} n# t          $ r d }Y nw xY wddt          dd fd}| dk    r_ |d          }|rNd} || |          r||fS |                    |           |t          || | ||d|t                              z  }||fS t          j	        |           }	|	r|	j
        t          k    r||fS d}
|	j        r# ||	j                                      d          }
t          |	j                  }| dk    rg d}|D ]} ||          }|sd| } || |          r"|                    |           |
p|	j        }| dk    rt!          ||	j        |
          }n| dk    rt#          ||	j        |
          }|t          || | |||||                    z  }||fS )!NFr   rK   r#   c                ,   t                      }|                    | d                                          }t          j                            | d                                          }|                    d          r|r|S |pt          | d          p|S )Nr   zop://)r   r{   r   r2  r3  rQ   ro  )r   env_filer   env_vals       r*   _get_env_prefer_dotenvz._seed_from_env.<locals>._get_env_prefer_dotenv  s    ::ll3##))++*..b))//11 >>'"" 	w 	N5k#r**5g5rU   r   rd  c                    dS rg  r   rh  s     r*   _is_source_suppressedz-_seed_from_env.<locals>._is_source_suppressed  rl  rU   r  r^   c                    	 ddl m}  ||           }n# t          $ r d }Y nw xY w|r!t          |                                          nd S )Nr   )get_secret_source)hermes_cli.env_loaderr  r)   rK   r   )r  r  source_labels      r*   _secret_source_for_envz._seed_from_env.<locals>._secret_source_for_env  ss    	 ??????,,W55LL 	  	  	 LLL	 ,8Bs<  &&(((dBs    ##)rM   r\   rL   rh   rM   rp   c                <    | ||||d} |          }|r||d<   |S )Nr  rD   r   )r\   r  rL   rh   rM   r   rD   r  s          r*   _env_payloadz$_seed_from_env.<locals>._env_payload  sI     "! #
 #
 /.w77 	5'4GO$rU   
openrouterOPENROUTER_API_KEYzenv:OPENROUTER_API_KEY)r\   r  rL   rh   r   r  rO   )rs  rt  rr  r~  zkimi-codingzair  )r  rK   r#   r^   )r\   rK   r  rK   rL   rK   rh   rK   rM   rK   r#   rp   )r  r  re  r  rS   r  rQ  r   r   r{   rM   base_url_env_varr  r  api_key_env_varsrl   r   r   )rJ   r   r`  r  r  r  r  rL   r\   r  env_urlenv_varsr  rh   r  s                 @r*   _seed_from_envr    s   G"uuN6 6 6 6,QQQQQQQ   	 	 	 	 	C C C C +       ( <&&';<< 	-F$$Xv66 /..v&&&}!00	  	
 
 
G &&#H--G 'g'+<<<&&G O(()ABBII#NNG,--H;
 
 
  
 
&&w// 	!!!  622 	6"""8g8}$$-eW5OQXYYHH,UG4NPWXXH=L!	  	

 

 
	
 N""s    ..Tprune_env_sourcesr  Set[str]r  c                   d	fdfd| D             }t          |          t          |           k    rdS || d d <   dS )
Nr   rW   r#   r   c                    | j                             d          rS t          | j         | j                  p
| j         dk    S )Nr~  r  )r\   rQ   r   rJ   )r   r  s    r*   _is_prunablez1_prune_stale_seeded_entries.<locals>._is_prunableU	  sJ     <""6** 	%$$ *%,GG -|},	
rU   c                d    g | ],}t          |j                  s|j        v s |          *|-S r   rV  )r   r   r  r  s     r*   rg  z/_prune_stale_seeded_entries.<locals>.<listcomp>e	  sX       U\** <>))|E"" * 	 *))rU   FTrH  )r  )r   r  r  r  r  s    `` @r*   _prune_stale_seeded_entriesr  O	  s    
 
 
 
 
 
       H 8}}G$$uGAAAJ4rU   c                   d}t                      }	 ddlm} n# t          $ r d }Y nw xY wt	          |           }|rt          |                    d          pd                                          }t          |                    d          pd                                                              d          }t          |                    d	          pd                                          }|rHd
| }	 || |	          s7|	                    |	           |t          || |	|	t          |||p|	d          z  }	 t                      }
|
r|
                    d          nd}t          |t                    rNt          |                    d          pd                                                                          }t          |                    d          pd                                                              d          }d}dD ]V}|                    |          }t          |t
                    r*|                                r|                                } nW|dk    r\|rZ|rXt!          |          }|| k    rCd}	 || |	          s5|	                    |	           |t          || |	|	t          ||dd          z  }n# t"          $ r Y nw xY w||fS )zJSeed a custom endpoint pool from custom_providers config and model config.Fr   rd  c                    dS rg  r   rh  s     r*   rk  z)_seed_custom_pool.<locals>._is_suppressed{	  rl  rU   r6   r   rh   r  rw   zconfig:r  modelNrJ   )r6   apir"  model_config)r  r  re  r  r  rK   r{   r   r  r  rQ  rS   r+   rP   r   r   r  r)   )r  r   r`  r  rk  	cp_configr6   rh   rw   r\   r   	model_cfgmodel_providermodel_base_urlmodel_api_keyr   r   matched_keys                     r*   _seed_custom_poolr  r	  sA   G"uuNJJJJJJJ   	 	 	 	 	
 ,H55I immI..4"55;;==y}}Z006B77==??FFsKK9==((.B//5577 	%t%%F!>(F33 ""6***="(%6(/$,!% 	   "$$+1;FJJw'''t	i&& 	 z!:!:!@bAAGGIIOOQQN z!:!:!@bAAGGIIPPQTUUNM'  MM!$$a%% !'')) $%GGIIME))n)):>JJ(**+F)>(F;; &**6222=#$"*0->0=,:)7 	$ $      N""s    ))=FK	 	
KKc                     pd                                                                  t                     }d |D             }t           fd|D                       } fd|D             }t           fd|D                       }|r\t	                                          d          }t          |t                    r|                               nd }t          |          } 	                    t                    r-t           |          \  }}	|p|p|}
|
t          ||	          z  }
nYt           |          \  }}t           |          \  }}|p|p|p|}
|
t          |||z  d          z  }
|
t           |          z  }
|
r;d	 |D             }t!           d
 t#          |d           D             ||z
             t%           |          S )Nr   c                    h | ]A}t          |t                    |                    d           ,|                    d           BS r  )rP   r   r{   r   s     r*   r   zload_pool.<locals>.<setcomp>	  sV       eT"" (-yy		$  rU   c              3  j   K   | ]-}t          |t                    ot          |          |k    V  .d S rs   )rP   r   r   r   r   rJ   s     r*   r   zload_pool.<locals>.<genexpr>	  s[       ! !  	7D!! 	O0(CCwN! ! ! ! ! !rU   c                F    g | ]}t                               |          S r   )rW   r   r  s     r*   rg  zload_pool.<locals>.<listcomp>	  s*    XXX))(G<<XXXrU   c           	   3     K   | ]s}t          |t                    oYt          |                    d           |                    dt                              |                    dt                    k    V  tdS )r]   rM   N)rP   r   rT   r{   rS   r  s     r*   r   zload_pool.<locals>.<genexpr>	  s       ' '  	7D!! 	9%KK''KK%677
 
 [[&788	9' ' ' ' ' 'rU   credential_poolFr  c                    h | ]	}|j         
S r   r  r   s     r*   r   zload_pool.<locals>.<setcomp>	  s    11158111rU   c                6    g | ]}|                                 S r   rf  r   s     r*   rg  zload_pool.<locals>.<listcomp>	  s     ZZZU]]__ZZZrU   c                    | j         S rs   r   )r  s    r*   rB  zload_pool.<locals>.<lambda>	  s    4= rU   rC  ra  )r   r   r!   r  r   r{   rP   r   r   rQ   r  r  r  r  r  ra  r"   r  r>  )rJ   raw_entriesdisk_idsraw_needs_sanitizationr   raw_needs_auth_normalizationactive_poolactive_entriescustom_changedcustom_sourcesr`  singleton_changedr  env_changedenv_sourcesnew_idss   `               r*   	load_poolr  	  s   B%%''--//H&x00K    H
 ! ! ! ! ! #! ! !  
 YXXXKXXXG#& ' ' ' ' #' ' ' $ $  $ < '((,,->??6@d6S6S]222Y]'+N';';$-.. A):8W)M)M&(Z,HZN.wGGG/DXw/W/W,,#1(G#D#D [" +  	 	 	.+#
 
 
 	

 	-h@@@ 
11111ZZ&>X>X*Y*Y*YZZZ 7*	
 	
 	
 	

 (G,,,rU   )r#   r$   )rJ   rK   rL   r
   rM   r
   r#   rK   )rL   rK   r   rK   r#   rK   )r   r   r#   rZ   )r\   rK   r#   r   )r   rc   r#   rZ   )r   r
   r#   ra   )r   rK   r#   ra   )r   r   r#   rp   )r   rW   r#   ra   )rw   rK   r#   rK   rs   )r   r$   )rh   r^   r  r^   r#   r^   )r#   r  )r  rK   r#   r   )rJ   rK   r#   rK   )r   r
   rJ   r^   rh   r^   r#   r   )r(  rK   r)  rp   r#   r*  )
r   r   rJ   rK   r\   rK   r   rp   r#   r   )rJ   rK   r   r   r#   r   )rJ   rK   r   r   r#   rb  )r   r   r  r  r  r   r#   r   )r  rK   r   r   r#   rb  )rJ   rK   r#   r>  )g__doc__
__future__r   loggingr2  r:   rG  r   r   r   dataclassesr   r   r   r   r   pathlibr	   typingr
   r   r   r   r   r   hermes_constantsr   r(   r   agent.secret_scoper   ro  agent.credential_persistencer   r   r  authr   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   	getLoggerr~   r6  r+   r  r   rq  	frozensetrm  r  rR   rS   r   SOURCE_MANUAL_DEVICE_CODEr  r  r  r  r  r   r   r   r  rz   rT   rW   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r'  rK  r<  r>  rQ  ra  r  r  r  r  r  r   rU   r*   <module>r     s   B B " " " " " "  				        				 2 2 2 2 2 2 2 2 2 2 ' ' ' ' ' ' ' '       8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 0 0 0 0 0 0 & & & & & & 8 8 8 8 8 8        # " " " " "                               " 
	8	$	$    	  
 # $ $ $   ( !-  ,::: " $ " 	  # #  ' 
   i     / / / / g g g g g g g gT   F F F FU U U U
) ) ) )   <   .   2   2 2 2 2
7 7 7 7 74    <         ( #	#D #D #D #D #D #DL )* %4
 4
 4
 4
nE E E E E E E EP(*# *# *# *#Z   DD# D# D# D#N
~# ~# ~# ~#J #	           FF# F# F# F#R?- ?- ?- ?- ?- ?-rU   