
    =<xjA             
         d Z ddlmZ ddlZddlZddlmZmZ ddlm	Z	m
Z
mZ  ej                  e      Z G d dej                        Ze G d d	             Zg d
ZdZ edddddddeh      Zg dZg dZg dZg dZg dZg dZg dZg dZg dZg dZg dZ g dZ!g dZ"d gZ#g d!Z$g d"Z% eh d#      Z&g d$Z'g d%Z(g d&Z)d'd'dd(dd)	 	 	 	 	 	 	 	 	 	 	 	 	 d7d*Z*dd+	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d8d,Z+d9d-Z,dd+	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d:d.Z-	 	 	 	 	 	 d;d/Z.	 	 	 	 	 	 	 	 	 	 d<d0Z/d=d1Z0d>d2Z1d?d3Z2d@d4Z3dAd5Z4dBd6Z5y)Ca  API error classification for smart failover and recovery.

Provides a structured taxonomy of API errors and a priority-ordered
classification pipeline that determines the correct recovery action
(retry, rotate credential, fallback to another provider, compress
context, or abort).

Replaces scattered inline string-matching with a centralized classifier
that the main retry loop in run_agent.py consults for every API failure.
    )annotationsN)	dataclassfield)AnyDictOptionalc                  l    e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZy)FailoverReasonu8   Why an API call failed — determines recovery strategy.authauth_permanentbilling
rate_limitupstream_rate_limit
overloadedserver_errortimeoutssl_cert_verificationcontext_overflowpayload_too_largeimage_too_largemodel_not_foundprovider_policy_blockedcontent_policy_blockedformat_errorinvalid_encrypted_content#multimodal_tool_content_unsupportedthinking_signaturelong_context_tier!oauth_long_context_beta_forbiddenllama_cpp_grammar_patternunknownN)__name__
__module____qualname____doc__r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r!        I/root/.hermes/venv/lib/python3.12/site-packages/agent/error_classifier.pyr
   r
      s    B D%N GJ 0 J!L G
 4 *+'O (O75 "L ;*O' .+(K% ; Gr'   r
   c                      e Zd ZU 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<    e	e
      Zded<   dZded<   dZded<   dZded<   dZded<   edd       Zy)ClassifiedErrorz>Structured classification of an API error with recovery hints.r
   reasonNOptional[int]status_codeOptional[str]providermodel strmessage)default_factoryzDict[str, Any]error_contextTbool	retryableFshould_compressshould_rotate_credentialshould_fallbackc                Z    | j                   t        j                  t        j                  hv S N)r+   r
   r   r   )selfs    r(   is_authzClassifiedError.is_auth_   s"    {{~22N4Q4QRRRr'   )returnr6   )r"   r#   r$   r%   __annotations__r-   r/   r0   r3   r   dictr5   r7   r8   r9   r:   propertyr>   r&   r'   r(   r*   r*   M   s    H!%K%"Hm"E=GS$)$$?M>? It!OT!%*d*!OT!S Sr'   r*   )zinsufficient creditsinsufficient_quotazinsufficient balancezcredit balancezcredits exhaustedzcredits have been exhaustedzno usable creditsztop up your creditszpayment requiredzbilling hard limitzexceeded your current quotazaccount is deactivatedzplan does not includezout of extra usagezout of fundszrun out of fundsbalance_depleted model_not_supported_on_free_tierznot available on the free tierzrequires available creditszbalance is too lowz$personal-team-blocked:spending-limitrC   billing_not_activepayment_requiredinsufficient_creditsno_usable_creditsrD   rE   )z
rate limitr   ztoo many requests	throttledzrequests per minuteztokens per minutezrequests per dayztry again inzplease retry afterresource_exhaustedzrate increased too quicklythrottlingexceptionztoo many concurrent requestsservicequotaexceededexception)r   ztemporarily overloadedz!service is temporarily overloadedz%service may be temporarily overloadedzserver is overloadedzserver overloadedzservice overloadedzservice is overloadedzupstream overloadedzcurrently overloadedzat capacityzover capacity)zusage limitquotazlimit exceededkey limit exceeded)z	try againretryz	resets atzreset inwaitzrequests remainingperiodicwindow)zrequest entity too largezpayload too largezerror code: 413)zimage exceedszimage too larger   zimage size exceedszimage dimensions exceedz"dimensions exceed max allowed sizezmax allowed size: 8000)ztext is not setz%tool message content must be a stringztool content must be a stringztool message must be a stringzexpected string, got listzexpected string, got arrayz tool_call.content must be string)zcontext lengthzcontext sizezmaximum contextztoken limitztoo many tokenszreduce the lengthzexceeds the limitzcontext windowzprompt is too longzprompt exceeds max length
max_tokenszmaximum number of tokenszexceeds the max_model_lenmax_model_lenzprompt lengthinput is too longzmaximum model lengthzcontext length exceededztruncating inputzslot context
n_ctx_slotu   超过最大长度u   上下文长度z.tokens in request more than max tokens allowedrV   zmax input tokenzinput tokenz*exceeds the maximum number of input tokens)	zis not a valid modelzinvalid modelzmodel not foundr   zdoes not existzno such modelzunknown modelzunsupported modelz(no endpoints found that support tool use)zunknown parameterzunsupported parameterzunrecognized request argumentinvalid_request_errorunknown_parameterunsupported_parameter)z.no endpoints available matching your guardrailz0no endpoints available matching your data policyz,no endpoints found matching your data policy)
z'flagged for possible cybersecurity riskztrusted access for cyberzviolates our usage policiesz violates openai's usage policieszyour request was flagged byz prompt was flagged by our safetyz+responses cannot be generated due to safetycontent_filterresponsibleaipolicyviolationnew_sensitive)	zinvalid api keyinvalid_api_keyauthenticationunauthorized	forbiddenzinvalid tokenztoken expiredztoken revokedzaccess denied	signature)zreturned an empty responsezempty response despite retriesz#provider returned an empty responsezmodel returning empty responseszempty response stream)z	timed outzturn timed outzrequest timed outzdeadline exceededzoperation timed outzupstream timed out>   SSLError	ReadErrorPoolTimeoutReadTimeoutSSLEOFErrorConnectErrorTimeoutErrorConnectTimeoutAPITimeoutErrorBrokenPipeErrorConnectionErrorSSLSyscallErrorSSLWantReadErrorSSLWantWriteErrorAPIConnectionErrorSSLZeroReturnErrorRemoteProtocolErrorConnectionResetErrorConnectionAbortedErrorServerDisconnectedError)zserver disconnectedzpeer closed connectionzconnection reset by peerzconnection was closedznetwork connection lostzunexpected eofzincomplete chunked read)zcertificate verify failedcertificate_verify_failedz&unable to get local issuer certificatezself-signed certificatezself signed certificatezcertificate has expiredz+hostname mismatch, certificate is not validz&unable to verify the first certificate)zbad record macz	ssl alertz	tls alertzssl handshake failureztlsv1 alertzsslv3 alertbad_record_mac	ssl_alert	tls_alerttls_alert_internal_errorz[ssl:r1   i@ )r/   r0   approx_tokenscontext_lengthnum_messagesc               
    t               t               j                  }|dk(  rdt               t	              }t               j                         }d}	d}
t        t              rGj                  di       }t        |t              rt        |j                  d      xs d      j                         }	|j                  di       }t        |t              r|j                  d      xs d}t        |t
              r|j                         rt	 d	dl}|j                  |      }t        |t              rN|j                  di       }t        |t              r,t        |j                  d      xs d      j                         }
|	s,t        j                  d      xs d      j                         }	|g}|	r|	|vr|j                  |	       |
r|
|vr|
|	vr|j                  |
       d
j!                  |      xs dj                         j                         }xs dj                         j                         }d0 fd}t#        fdt$        D              r |t&        j(                  dd      S dk(  r)dv r%dv sdv sdv r |t&        j*                  dd      S dk(  r!dv rdv r |t&        j,                  dd      S dk(  r!dv rdv r |t&        j.                  dd      S dk(  r)dv sdv sdv rdv r |t&        j0                  dd      S dv sdv rd v r |t&        j2                  dd      S t5        |||||||!
      }||S d	d"lm} t         |      r |t&        j:                  d#      S |rt=        ||      }||S t?        ||||$      }||S t#        fd%t@        D              r |t&        jB                  dd      S t#        fd&tD        D              r |t&        jF                  d#      S t#        fd'tH        D              }|rxsvd	d(l%m&}  |       |t&        jF                  d#      S ||d)z  kD  xs |d*k  xr |d+kD  xs |d,kD  }|r |t&        jN                  dd      S  |t&        jF                  d#      S |d-k(  r!d.v rd/v r |t&        jF                  dd      S |tP        v st         tR        tT        tV        f      r |t&        jF                  d#      S  |t&        jX                  d#      S # j                  t        f$ r Y w xY w)1u  Classify an API error into a structured recovery recommendation.

    Priority-ordered pipeline:
      1. Special-case provider-specific patterns (thinking sigs, tier gates)
      2. HTTP status code + message-aware refinement
      3. Error code classification (from body)
      4. Message pattern matching (billing vs rate_limit vs context vs auth)
      5. SSL/TLS transient alert patterns → retry as timeout
      6. Server disconnect + large session → context overflow
      7. Transport error heuristics
      8. Fallback: unknown (retryable with backoff)

    Args:
        error: The exception from the API call.
        provider: Current provider name (e.g. "openrouter", "anthropic").
        model: Current model slug.
        approx_tokens: Approximate token count of the current context.
        context_length: Maximum context length for the current model.

    Returns:
        ClassifiedError with reason and recovery action hints.
    NRateLimitError  r1   errorr3   metadatarawr    c                `    | t              d}|j                  |       t        di |S )N)r+   r-   r/   r0   r3   r&   )_extract_messageupdater*   )r+   	overridesdefaultsbodyr   r0   r/   r-   s      r(   _resultz#classify_api_error.<locals>._result  s<    & 't4
 		"***r'   c              3  &   K   | ]  }|v  
 y wr<   r&   .0p	error_msgs     r(   	<genexpr>z%classify_api_error.<locals>.<genexpr>  s     
Da1	>
D   FTr7   r:     thinkingrb   zcannot be modifiedzmust remain as they werer7   r8   zextra usagezlong contextzlong context betaznot yet availablezerror parsing grammarzjson-schema-to-grammarzunable to generate parsertemplatez'do not have an active grok subscriptionzout of available resourcesgrokr/   r0   r|   r}   r~   	result_fn)MoAPresetNotFoundErrorr7   )r|   r}   r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z%classify_api_error.<locals>.<genexpr>E       
=a1	>
=r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z%classify_api_error.<locals>.<genexpr>T  s     
;a1	>
;r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z%classify_api_error.<locals>.<genexpr>]  s     L1YLr   )!get_reasoning_stale_timeout_floorg333333?  i    RuntimeErrorzconsecutive stale attemptszaborting this call)r+   r
   r?   r*   )-_extract_status_codetyper"   _extract_error_body_extract_error_coder2   lower
isinstancerA   getstripjsonloadsJSONDecodeError	TypeErrorappendjoinany _CONTENT_POLICY_BLOCKED_PATTERNSr
   r   r   r   r   r    r   _classify_by_statusagent.errorsr   r   _classify_by_error_code_classify_by_message_SSL_CERT_VERIFY_PATTERNSr   _SSL_TRANSIENT_PATTERNSr   _SERVER_DISCONNECT_PATTERNSagent.reasoning_timeoutsr   r   _TRANSPORT_ERROR_TYPESri   rm   OSErrorr!   )r   r/   r0   r|   r}   r~   
error_type
error_code_raw_msg	_body_msg_metadata_msg_err_obj	_metadata	_raw_jsonr   _inner
_inner_errpartsprovider_lowermodel_lowerr   
classifiedr   is_disconnectr   is_larger   r   r-   s   ```                       @@@r(   classify_api_errorr   1  s   > 'u-Ke%%J z-==u%D$T*J 5z!HIM$88GR(h%HLL39r:@@BI Z4I)T*%MM%06B	i-)//2C#!%I!6%fd3)/GR)@J)*d;03JNN94M4SQS0T0Z0Z0\ DHHY/526<<>IJEYh.Yh6=PY;Y]#In"++-335N;B%%'--/K	+ 	+( 
D#C
DD11 
 	
2 	s)#9$#y0)Y6 --!
 	
 	sY&i',, 
 	
 	s9,9,<<!
 	
 	s#y0'94+y8)+ 44!
 	
4 	2Y>(I5&I:M 
 	
 (J#;'%

 !
 4%/0~55GG ,ZGL
! &:#%	J  
=#<
==00!
 	
 
;#:
;;~-->> L0KLLM[$ 	O,U3?>11TBB !>C#77 
f$W-&*@*VLSVDV 	 // $ 
 ~-->> 	n$(I5 I-"" 
 	
 ++z%,P_ahAi/j~-->> >))T::O	 !00)< s   A3T% %T>=T>)r~   c                  | dk(  r |	t         j                  ddd      S | dk(  ro|dk(  r|j                         t        k(  s dv sdv st	        fd	t
        D              r |	t         j                  ddd      S  |	t         j                  dd
      S | dk(  rt        |	      S | dk(  rt	        fdt
        D              r |	t         j                  ddd      S t	        fdt        D              r |	t         j                  dd
      S t	        fdt        D              r |	t         j                  dd
      S  |	t         j                  d      S | dk(  r |	t         j                  dd      S | dk(  rt	        fdt        D              r |	t         j                  d      S t!        ||      r.t#        |      }
|
rd|
ini } |	t         j$                  ddd|      S  |	t         j&                  ddd      S | dk(  rt)        ||||||||		      S | dv rt	        fdt*        D              s|j                         dv r |	t         j,                  dd
      S t	        fdt.        D              r |	t         j0                  dd      S t	        fdt2        D              r |	t         j4                  dd      S  |	t         j0                  d      S | dv rzt	        fdt.        D              r |	t         j0                  dd      S t	        fd t2        D              r |	t         j4                  dd      S  |	t         j                  d      S | d!k(  r |	t         j6                  d      S d| cxk  rd"k  rn n |	t         j,                  dd
      S d"| cxk  rd#k  rn y$ |	t         j0                  d      S y$)%zAClassify based on HTTP status code with message-aware refinement.i  FTr7   r9   r:   i  z	xai-oauthrO   zspending limitc              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z&_classify_by_status.<locals>.<genexpr>  s     =a1	>=r   r   i  i  c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z&_classify_by_status.<locals>.<genexpr>  s     9!qI~9r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z&_classify_by_status.<locals>.<genexpr>       I!qI~Ir   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z&_classify_by_status.<locals>.<genexpr>  s     A!qI~Ar   r   i  r   r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z&_classify_by_status.<locals>.<genexpr>  s     <!qI~<r   upstream_provider)r7   r9   r:   r5   r   r   >       c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z&_classify_by_status.<locals>.<genexpr>B  s     E1YEr   >   rY   rX   rZ   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z&_classify_by_status.<locals>.<genexpr>S  r   r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z&_classify_by_status.<locals>.<genexpr>Y       B!qI~Br   >       c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z&_classify_by_status.<locals>.<genexpr>f  r   r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z&_classify_by_status.<locals>.<genexpr>l  r   r   i  r   X  N)r
   r   r   _XAI_SPENDING_LIMIT_ERROR_CODEr   _BILLING_PATTERNSr   _classify_402!_PROVIDER_POLICY_BLOCKED_PATTERNSr   _MODEL_NOT_FOUND_PATTERNSr   r!   r   _OVERLOADED_PATTERNSr   _is_openrouter_upstream_error_extract_upstream_provider_namer   r   _classify_400_REQUEST_VALIDATION_PATTERNSr   !_EMPTY_PROVIDER_RESPONSE_PATTERNSr   _CONTEXT_OVERFLOW_PATTERNSr   r   )r-   r   r   r   r/   r0   r|   r}   r~   r   r   ctxs    `          r(   r   r     s    c %) 	
 	
 c
 K'$$&*HH#y09,=+<==&&)- $	   
 	
 cY	22c
 9'899&&)- $	  I'HII66 % 
 A'@AA.. $  ""
 	

 c,, 
 	
 c <';<<))  )x8 ? E>O&(9:UWC22). $!  %%%) 	
 	
 cz4U')%
 	
 j  E(DEE! &? ? ++ $  I'HII++ % 
 B'ABB// $ 
 44EEj 
 I'HII++ % 
 B'ABB// $ 
 22dCC c//4@@ kC'' 
 	
 kC  44EEr'   c                     t         fdt        D              }t         fdt        D              }|r|r |t        j                  ddd      S  |t        j
                  ddd      S )u  Disambiguate 402: billing exhaustion vs transient usage limit.

    The key insight from OpenClaw: some 402s are transient rate limits
    disguised as payment errors.  "Usage limit, try again in 5 minutes"
    is NOT a billing problem — it's a periodic quota that resets.
    c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z _classify_402.<locals>.<genexpr>       HQ!y.Hr   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z _classify_402.<locals>.<genexpr>  s     V!qI~Vr   Tr   F)r   _USAGE_LIMIT_PATTERNS_USAGE_LIMIT_TRANSIENT_SIGNALSr
   r   r   )r   r   has_usage_limithas_transient_signals   `   r(   r   r     sn     H2GHHOV7UVV/%%%) 	
 	
 !%	 r'   c               $    t         fdt        D              r |t        j                  d      S t         fdt        D              r |t        j
                  d      S |xs dj                         }	|	dk(  sd v sd v rd v sd	 v r |t        j                  dd
      S t         fdt        D              s|	dv r |t        j                  d
d      S t         fdt        D              r |t        j                  dd
      S t         fdt        D              r |t        j                  dd      S t         fdt        D              r |t        j                  d
d
      S t         fdt         D              r |t        j"                  d
d      S t         fdt$        D              r |t        j&                  ddd      S t         fdt(        D              r |t        j*                  d
dd      S d}
t-        |t.              r|j1                  di       }t-        |t.              r:t3        |j1                  d      xs d      j5                         j                         }
|
s:t3        |j1                  d      xs d      j5                         j                         }
t7        |
      dk  xs |
dv }||dz  kD  xs |dk  xr |dkD  xs |dkD  }|r|r |t        j                  dd      S  |t        j                  d
d      S )uH   Classify 400 Bad Request — context overflow, format error, or generic.c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z _classify_400.<locals>.<genexpr>       
Ea1	>
Er   Tr   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z _classify_400.<locals>.<genexpr>  r   r   r1   r   zencrypted content for itemzcould not be verifiedz0could not decrypt the provided encrypted_contentFr   c              3  0   K   | ]  }|d k7  r|v   yw)rX   Nr&   r   s     r(   r   z _classify_400.<locals>.<genexpr>  s%      -q++ N -s   >   rY   rZ   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z _classify_400.<locals>.<genexpr>  r   r   r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z _classify_400.<locals>.<genexpr>       
>a1	>
>r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z _classify_400.<locals>.<genexpr>  r   r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z _classify_400.<locals>.<genexpr>  r   r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z _classify_400.<locals>.<genexpr>#       
8a1	>
8r   r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z _classify_400.<locals>.<genexpr>*       
5a1	>
5r   r   r3      >   r1   r   g?r   i8 P   )r   !_MULTIMODAL_TOOL_CONTENT_PATTERNSr
   r   _IMAGE_TOO_LARGE_PATTERNSr   r   r   r   r   r   r   r   r   r   r   r   r   _RATE_LIMIT_PATTERNSr   r   r   r   rA   r   r2   r   len)r   r   r   r/   r0   r|   r}   r~   r   error_code_lowererr_body_msgerr_obj
is_genericr   s   `             r(   r   r     s   * 
E#D
EE>>
 	
 
=#<
==**
 	
 #(b//177&)3(I5'94=J44!
 	
0 	 -$@ - 	-MM'' 
 	
 
E#D
EE''!
 	
 
>#=
>>++ 
 	
 
E#D
EE22!
 	

 
=#<
==** 
 	
 
8#7
88%%%) 	
 	
 
5#4
55""%) 	
 	
 L$((7B'gt$w{{95;<BBDJJLLtxx	28b9??AGGIL\"R'H<=+HJ ~33 & Qme&;&P|b?P  h++ 
 	
 ## r'   c                R   | j                         }|dv r |t        j                  dd      S |t        v r |t        j                  ddd      S |dv r |t        j
                  dd      S |dv r |t        j                  dd	      S |d
k(  r |t        j                  dd      S y)z:Classify by structured error codes from the response body.>   rJ   rK   rate_limit_exceededT)r7   r9   Fr   >   invalid_modelr   model_not_availabler   >   max_tokens_exceededcontext_length_exceededr   r   N)r   r
   r   _BILLING_ERROR_CODESr   r   r   r   )r   r   r   
code_lowers       r(   r   r   U  s     !!#JOO%%%)
 	
 ))""%) 	
 	
 PP** 
 	
 GG++ 
 	
 0044!
 	
 r'   c               l    t         fdt        D              r |t        j                  dd      S t         fdt        D              r |t        j
                  d      S t         fdt        D              r |t        j                  d      S t         fdt        D              }|rNt         fdt        D              }|r |t        j                  ddd	      S  |t        j                  d
dd	      S t         fdt        D              r |t        j                  d      S t         fdt        D              r |t        j                  d
dd	      S t         fdt        D              r |t        j                  ddd	      S t         fdt         D              r |t        j"                  dd
      S t         fdt$        D              r |t        j&                  dd      S t         fdt(        D              r |t        j*                  d
dd	      S t         fdt,        D              r |t        j.                  d
d
      S t         fdt0        D              r |t        j2                  d
d      S t         fdt4        D              r |t        j6                  d      S y)zJClassify based on error message patterns when no status code is available.c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z'_classify_by_message.<locals>.<genexpr>  s     
?a1	>
?r   Tr   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z'_classify_by_message.<locals>.<genexpr>  r   r   r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z'_classify_by_message.<locals>.<genexpr>  r   r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z'_classify_by_message.<locals>.<genexpr>  r   r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z'_classify_by_message.<locals>.<genexpr>  s     "Za1	>"Zr   r   Fc              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z'_classify_by_message.<locals>.<genexpr>  r  r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z'_classify_by_message.<locals>.<genexpr>  r  r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z'_classify_by_message.<locals>.<genexpr>  r  r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z'_classify_by_message.<locals>.<genexpr>  r   r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z'_classify_by_message.<locals>.<genexpr>  r  r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z'_classify_by_message.<locals>.<genexpr>  s     
2a1	>
2r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z'_classify_by_message.<locals>.<genexpr>  r   r   r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z'_classify_by_message.<locals>.<genexpr>  r   r   c              3  &   K   | ]  }|v  
 y wr<   r&   r   s     r(   r   z'_classify_by_message.<locals>.<genexpr>
  r   r   N)r   _PAYLOAD_TOO_LARGE_PATTERNSr
   r   r
  r   r  r   r   r   r   r   r   r   r   r  r   r   r   r   _AUTH_PATTERNSr   r   r   r   r   _TIMEOUT_MESSAGE_PATTERNSr   )r   r   r|   r}   r   r   r   s   `      r(   r   r     s    
?#>
??,, 
 	
 
E#D
EE>>
 	
 
=#<
==**
 	
 H2GHHO""Z;Y"ZZ)))- $	  ""%) 	
 	
 
8#7
88%%
 	
 
5#4
55""%) 	
 	
 
8#7
88%%%) 	
 	
 
E#D
EE''!
 	
 
>#=
>>++ 
 	
 
2>
22%) 	
 	
 
E#D
EE22!
 	
 
=#<
==** 
 	
 
=#<
==//4@@r'   c                   | }t        d      D ]v  }t        |dd      }t        |t              r|c S t        |dd      }t        |t              rd|cxk  rdk  r|c S  t        |dd      xs t        |dd      }|||u r y|}x y)	z?Walk the error and its cause chain to find an HTTP status code.   r-   Nstatusd   r   	__cause____context__)rangegetattrr   int)r   current_codecauses        r(   r   r     s    G1X wt4dC Kw$/dC SD%63%6K &7 d3\wwW[7\=EW,  r'   c                B   | }t        d      D ]  }t        |dd      }t        |t              r|c S t        |dd      }|&	 |j	                         }t        |t              r|c S 	 t        |dd      xs t        |dd      }|||u r i S |} i S # t
        $ r Y 6w xY w)zKExtract the structured error body from an SDK exception or its cause chain.r-  r   Nresponser0  r1  )r2  r3  r   rA   r   	Exception)r   r5  r6  r   r:  	json_bodyr8  s          r(   r   r   %  s    G1X w-dD!K7J5$MMO	i.$$ / d3\wwW[7\=EW,I !" I  s   !B	BBc                   | sydd}| j                  di       }t        |t              r|j                  d      xs |j                  d      xs d}t        |t              r3|j	                         r#|j	                         dk7  r|j	                         S |j                  d      }t        |t              rA|j	                         j                  d      r"d	d
l}	 |j                  |      } ||      }|r|S | j                  d      xs | j                  d      xs d}t        |t        t        f      r"t        |      j	                         }|r|dk7  r|S y# |j                  t        f$ r d
}Y w xY w)z4Extract an error code string from the response body.r1   c                    t        | t              sy| j                  di       }t        |t              rk|j                  d      xs |j                  d      xs d}t        |t              r3|j	                         r#|j	                         dk7  r|j	                         S | j                  d      xs | j                  d      xs d}t        |t        t
        f      r"t        |      j	                         }|r|dk7  r|S y)zAExtract a code/type from a nested error payload dict (defensive).r1   r   r7  r   400r   )r   rA   r   r2   r   r4  )payloadpayload_errornestedr7  texts        r(   _code_from_payloadz/_extract_error_code.<locals>._code_from_payloadA  s    '4(GR0mT*"&&v.Q-2C2CF2KQrF&#&6<<>fllnPU>U||~%{{6"Egkk,&?E2dS#J't9??$Dr'   r   r7  r   r?  r3   {r   Nr   )r?   r2   )r   r   rA   r2   r   
startswithr   r   r   r   r4  )	r   rD  	error_objr7  r3   r   innernested_coderC  s	            r(   r   r   <  s@     "%I)T"}}V$C	f(=CdC TZZ\djjle6K::<
 --	*gs#(B(B3(G

7+ -U3K"" 88F;txx5;D$c
#4y DEMK (()4 s   E E21E2c                z   |r|j                  di       }t        |t              rE|j                  dd      }t        |t              r#|j	                         r|j	                         dd S |j                  dd      }t        |t              r#|j	                         r|j	                         dd S t        |       dd S )z+Extract the most informative error message.r   r3   r1   Nr   )r   r   rA   r2   r   )r   r   rG  msgs       r(   r   r   n  s     HHWb)	i&--	2.C#s#		yy{4C((hhy"%c3CIIK99;t$$u:dsr'   c                   t        | t              sy|xs dj                         j                         }| j	                  d      }t        |t              syt        |j	                  d      xs d      j                         j                         }|dk7  ry|dk(  ry|j	                  d      }t        |t              r	d	|v sd
|v ryy)u  Detect OpenRouter's aggregator-wrapped upstream provider errors.

    OpenRouter returns errors from upstream model providers (DeepSeek,
    Anthropic, etc.) wrapped with the outer message "Provider returned error"
    and the real error nested in ``metadata.raw``. This signal means the
    user's OpenRouter key is healthy — the upstream provider is the one that
    failed — so credential rotation is the wrong recovery.
    Fr1   r   r3   zprovider returned error
openrouterTr   r   provider_name)r   rA   r   r   r   r2   )r   r/   r   err	outer_msgr   s         r(   r   r   ~  s     dD!n"++-335N
((7
Cc4 CGGI&,"-335;;=I-- %wwz"H(D!_8r'   c                0   t        | t              sy| j                  d      }t        |t              sy|j                  d      }t        |t              sy|j                  d      }t        |t              r |j	                         r|j	                         S y)zCPull the upstream provider name out of OpenRouter's error metadata.Nr   r   rN  )r   rA   r   r2   r   )r   rO  r   names       r(   r   r     st    dD!
((7
Cc4 wwz"Hh%<<(D$zz|r'   )r   r;  r/   r2   r0   r2   r|   r4  r}   r4  r~   r4  r?   r*   )r-   r4  r   r2   r   r2   r   rA   r/   r2   r0   r2   r|   r4  r}   r4  r~   r4  r?   Optional[ClassifiedError])r   r2   r?   r*   )r   r2   r   r2   r   rA   r/   r2   r0   r2   r|   r4  r}   r4  r~   r4  r?   r*   )r   r2   r   r2   r?   rS  )
r   r2   r   r2   r|   r4  r}   r4  r?   rS  )r   r;  r?   r,   )r   r;  r?   rA   )r   rA   r?   r2   )r   r;  r   rA   r?   r2   )r   r   r/   r2   r?   r6   )r   r   r?   r.   )6r%   
__future__r   enumloggingdataclassesr   r   typingr   r   r   	getLoggerr"   loggerEnumr
   r*   r   r   	frozensetr  r  r   r   r   r)  r  r
  r   r   r   r   r   r*  _THINKING_SIG_PATTERNSr   r+  r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r&   r'   r(   <module>r^     s	  	 #   ( & &			8	$
0TYY 0j S S S4 @ "H 
 !&"	" 	  8   	"  
 .% ! ( V :  4% !.$  >
  % !  # $  4 ,	 6 0  m;m; m; 	m;
 m; m; m; m;x hhh h 	h h h h h h hVL eee e
 e e e e e eT** #**^III 	I
 I I\&./d <r'   