
    sjZ                   N   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dZ G d dej                  Ze G d	 d
                      Zg dZdZdZdZdZ ed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!d[d'Z"d(Z#d)d*d+d,d-d.e#gZ$g d/Z%g d0Z&g d1Z'g d2Z(d3gZ)g d4Z*g d5Z+g d6Z, eh d7          Z-g d8Z.g d9Z/g d:Z0d;d;dd<dd=d\dDZ1ddEd]dKZ2d^dLZ3ddEd_dMZ4d`dNZ5dadPZ6dbdRZ7dcdSZ8dddTZ9dedUZ:dfdWZ;dgdYZ<dS )ha  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Optionalprovider_stream_non_json_datac                  n    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dS )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"        :/home/agent/.hermes/hermes-agent/agent/error_classifier.pyr   r      s        BB D%N GJ 0 J!L G
 4 *+'O (O75 "L ;*O' .+(K% ; GGGr(   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edd            ZdS )ClassifiedErrorz>Structured classification of an API error with recovery hints.r   reasonNOptional[int]status_codeOptional[str]providermodel strmessage)default_factoryDict[str, Any]error_contextTbool	retryableFshould_compressshould_rotate_credentialshould_fallbackreturnc                @    | j         t          j        t          j        hv S N)r,   r   r   r   selfs    r)   is_authzClassifiedError.is_authe   s    {~2N4QRRRr(   c                P    t          | j                            d                    S )zTrue when a ``billing`` verdict rests on an ambiguous body.

        Anthropic's "out of extra usage" 400 can also be a content-filter
        rejection (#82154); surfaces must hedge rather than assert exhaustion.
        billing_unverified)r8   r7   getr@   s    r)   rD   z"ClassifiedError.billing_unverifiedi   s$     D&**+?@@AAAr(   )r=   r8   )r#   r$   r%   r&   __annotations__r.   r0   r1   r4   r   dictr7   r9   r:   r;   r<   propertyrB   rD   r'   r(   r)   r+   r+   S   s        HH!%K%%%%"H""""EG$)E$$?$?$?M???? I!O!!!!%*****!O!!!!S S S XS B B B XB B Br(   r+   )zinsufficient creditsinsufficient_quotazinsufficient balancezcredit balancezcredits exhaustedzcredits have been exhaustedzrequires available creditszaccount balance is too lowzno usable creditsztop up your creditszpayment requiredzbilling hard limitzexceeded your current quotazaccount is deactivatedzplan does not includeout of extra usagezout of fundszrun out of fundsbalance_depleted model_not_supported_on_free_tierznot available on the free tier)rJ   	error_msgr3   r=   r6   c                R     t           fdt          D                       rdddS i S )zBerror_context marking a billing verdict as unverified (see above).c              3      K   | ]}|v V  	d S r?   r'   .0prM   s     r)   	<genexpr>z-_billing_ambiguity_context.<locals>.<genexpr>   '      
@
@a1	>
@
@
@
@
@
@r(   T)rD   possible_content_filter)any_UNVERIFIED_BILLING_PATTERNS)rM   s   `r)   _billing_ambiguity_contextrX      s=    

@
@
@
@#?
@
@
@@@ M&*tLLLIr(   z$personal-team-blocked:spending-limitrI   billing_not_activepayment_requiredinsufficient_creditsno_usable_creditsrK   rL   member_spend_cap_exceeded)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
throttling)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request_too_largez request exceeds the maximum size)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 allowedrl   zmax input tokenzinput tokenz*exceeds the maximum number of input tokenszmaximum allowed input length)	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 user1   r0   r8   c                    | pd                                 }|rd|v rdS 	 ddlm} t           ||pd                                 |                    S # t          $ r Y dS w xY w)u  True when a bare model id is only known to the provider as ``vendor/id``.

    Some providers answer a malformed model id with a naked 404 that names
    nothing — NVIDIA NIM returns ``404 page not found`` for a bare
    ``nemotron-3-ultra-550b-a55b``, indistinguishable from a bad endpoint
    path. Consulting the curated catalogue tells the two apart: if the id
    carries no ``/`` but the catalogue has exactly one entry ending in
    ``/<id>``, the prefix was dropped and the failure is deterministic.

    Never guesses — an id absent from the catalogue (a local NIM container,
    a proxied model) returns False so genuine endpoint problems keep their
    retryable ``unknown`` classification.
    r2   /Fr   )suggest_prefixed_model_id)striphermes_cli.model_normalizerp   r8   	Exception)r1   r0   namerp   s       r)   _model_id_missing_known_prefixru   |  s     KR  D 3$;;uHHHHHH--x~2.D.D.F.FMMNNN   uus   2A 
A! A!zno user query foundzmust have non-empty contentzmessages must have non-emptyinvalid_request_bodyz%text content blocks must be non-emptyzcontent field is requiredz*messages: at least one message is required)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gateway_auth_failed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)zconnection refusedeconnrefusedzno route to hostznetwork is unreachableznetwork unreachablezname or service not knownz$temporary failure in name resolutionznodename nor servname providedzgetaddrinfo failedzgetaddrinfo enotfound	eai_againzfetch failedzfailed to fetchzupstream connect error>   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:r2   i@ )r0   r1   approx_tokenscontext_lengthnum_messageserrorrs   r   intr   r   c                   ! t                     !t                     j        }!|dk    rd!t                     t	                    }t                                                     }d}	d}
t          t                    r	                    di           }t          |t                    rIt          |	                    d          pd                                          }	|	                    di           }t          |t                    r|	                    d          pd}t          |t
                    r|
                                r	 d	dl}|                    |          }t          |t                    ra|	                    di           }t          |t                    r6t          |	                    d          pd                                          }
n# |j        t          f$ r Y nw xY w|	s6t          	                    d          pd                                          }	|g}|	r|	|vr|                    |	           |
r|
|vr|
|	vr|                    |
           d
                    |           pd
                                                                }pd
                                                                }d; !fd}	 d	dlm}  |!||  |||          }n4# t&          $ r'}t(                              d|           d}Y d}~nd}~ww xY w|@|                    d          }t(                              d|j        !            ||fi |S t3           fdt4          D                       r |t6          j        dd          S !dk    r(d v r$d v sd v sd v r |t6          j        dd          S !dk    r d v rd v r |t6          j        dd          S !dk    r d  v rd! v r |t6          j        dd          S !dk    rd" v pd# v pd$ v od% v }nd}|r!t@           vr |t6          j!        dd          S d& v sd' v rd( v r |t6          j"        dd          S !tG          ! |||||||)
  
        }||S |d*k    r:d+t                     v sd,t                     v r |t6          j$        dd          S d	d-l%m&} t           |          r |t6          j'        d.          S |rtQ          | |          }||S tS           ||||/          }||S t3           fd0tT          D                       r |t6          j+        dd          S t3           fd1tX          D                       r |t6          j-        d.          S t3           fd2t\          D                       }|rv!std	d3l/m0}  |           |t6          j-        d.          S ||d4z  k    p|d5k    o|d6k    p|d7k    }|r |t6          j1        dd          S  |t6          j-        d.          S |d8k    r d9 v rd: v r |t6          j-        dd          S |td          v s"t           tf          th          tj          f          r |t6          j-        d.          S  |t6          j6        d.          S )<u  Classify an API error into a structured recovery recommendation.

    Priority-ordered pipeline:
      0. Plugin ``transform_api_error_classification`` hooks (first valid result wins)
      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  r2   r   r4   metadatarawr    r,   r   r=   r+   c                r    | t                    d}|                    |           t          di |S )N)r,   r.   r0   r1   r4   r'   )_extract_messageupdater+   )r,   	overridesdefaultsbodyr   r1   r0   r.   s      r)   _resultz#classify_api_error.<locals>._result  sP    & 't44
 
 		"""*****r(   )get_plugin_error_classification)r0   r1   r.   
error_type
error_codeerror_message
error_bodyr   r   r   r   z+Plugin error classification unavailable: %sz@API error classified by plugin hook: %s (provider=%s, status=%s)c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z%classify_api_error.<locals>.<genexpr>T  s'      
D
Da1	>
D
D
D
D
D
Dr(   FTr9   r<     thinkingr   zcannot be modifiedzmust remain as they werer9   r:   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r0   r1   r   r   r   	result_fnmoaz.'types.SimpleNamespace' object is not iterablez7'types.SimpleNamespace' object has no attribute 'index')MoAPresetNotFoundErrorr9   )r   r   r   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z%classify_api_error.<locals>.<genexpr>  '      
=
=a1	>
=
=
=
=
=
=r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z%classify_api_error.<locals>.<genexpr>(  s'      
;
;a1	>
;
;
;
;
;
;r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z%classify_api_error.<locals>.<genexpr>1  s'      LL1YLLLLLLr(   )!get_reasoning_stale_timeout_floorg333333?  i    RuntimeErrorzconsecutive stale attemptszaborting this call)r,   r   r=   r+   )7_extract_status_codetyper#   _extract_error_body_extract_error_coder3   lower
isinstancerG   rE   rq   jsonloadsJSONDecodeError	TypeErrorappendjoinhermes_cli.pluginsr   rs   loggerdebugpopinfovaluerV    _CONTENT_POLICY_BLOCKED_PATTERNSr   r   r   r   r    _NO_USER_QUERY_SIGNALr!   r   _classify_by_statusr   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_TYPESr   r   OSErrorr"   )"r   r0   r1   r   r   r   r   r   _raw_msg	_body_msg_metadata_msg_err_obj	_metadata	_raw_jsonr   _inner
_inner_errpartsprovider_lowermodel_lowerr   r   plugin_classificationexcr,   _llama_cpp_grammar_hit
classifiedr   is_disconnectr   is_larger   rM   r.   s"   ```                            @@@r)   classify_api_errorr     sC	   @ 'u--Ke%J z-===u%%D$T**J 5zz!!HIM$ ?88GR((h%% 	HLL339r::@@BBI Z44I)T** %MM%006B	i-- 	)//2C2C 	#!%I!6!6%fd33 ])/GR)@)@J)*d;; ]03JNN94M4M4SQS0T0T0Z0Z0\0\ 0)<    	?DHHY//5266<<>>IJE  Yh..Y $h66=PY;Y;Y]###In"++--3355N;B%%''--//K	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+(%FFFFFF ? ?#!!#')%!
 !
 !
  % % %BCHHH $% (&**844NL(K	
 	
 	
 wv77!6777 
D
D
D
D#C
D
D
DDD 
w1 
 
 
 	
2 	s)##9$$#y00)Y66 w-!
 
 
 	
 	sY&&i''w, 
 
 
 	
 	s9,,9,,w<!
 
 
 	
, c#y0 '94 ,y8 ,)+ 	 "'
!22w4!
 
 
 	
4 	2Y>>(I55&I:M:Mw 
 
 
 	
 (J#;'%
 
 

 !
 8CJJFFDE

RRw'!
 
 
 	
 433333%/00 Hw~5GGGG  ,ZGLL
! &:#%	  J  
=
=
=
=#<
=
=
=== 
w0!
 
 
 	
 
;
;
;
;#:
;
;
;;; ?w~->>>> LLLL0KLLLLLM !?[ !?$ 	ONNNNN,,U33?7>1TBBBB !>C#77 
f$W-&*@*VLSVDV 	  	7/ $   
 w~->>>> 	n$$(I55 I--w" 
 
 
 	
 +++z%,P_ahAi/j/j+w~->>>> 7>)T::::s+   BG+ +G?>G?'L 
L5L00L5)r   r.   r   r   rG   Optional[ClassifiedError]c                  | dk    r |	t           j        ddd          S | dk    r||dk    r|                                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          ||          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#          ||          r1t%          |          }
|
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|                                dv r |	t           j        dd
          S t	          fdt0          D                       r |	t           j        dd          S t	          fdt4          D                       r |	t           j        dd          S  |	t           j        d          S | dv rt	          fdt0          D                       r |	t           j        dd          S t	          fd t4          D                       r |	t           j        dd          S  |	t           j        d          S | d!k    r |	t           j        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 n |	t           j        d          S d$S )%zAClassify based on HTTP status code with message-aware refinement.i  FTr9   r;   r<   i  z	xai-oauthrd   zspending limitc              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z&_classify_by_status.<locals>.<genexpr>  s'      ==a1	>======r(   r   i  i  c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z&_classify_by_status.<locals>.<genexpr>  s'      99!qI~999999r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z&_classify_by_status.<locals>.<genexpr>  '      II!qI~IIIIIIr(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z&_classify_by_status.<locals>.<genexpr>  s'      AA!qI~AAAAAAr(   r   i  r   r   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z&_classify_by_status.<locals>.<genexpr>  s'      <<!qI~<<<<<<r(   upstream_providerr9   r;   r<   r7   r   r   >       c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z&_classify_by_status.<locals>.<genexpr>"  s'      EE1YEEEEEEr(   >   rx   rw   ry   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z&_classify_by_status.<locals>.<genexpr>3  r   r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z&_classify_by_status.<locals>.<genexpr>9  '      BB!qI~BBBBBBr(   >       c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z&_classify_by_status.<locals>.<genexpr>F  r   r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z&_classify_by_status.<locals>.<genexpr>L  r	  r(   i  r  X  N)r   r   r   _XAI_SPENDING_LIMIT_ERROR_CODErV   _BILLING_PATTERNSr   _classify_402!_PROVIDER_POLICY_BLOCKED_PATTERNSr   _MODEL_NOT_FOUND_PATTERNSr   ru   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.   rM   r   r   r0   r1   r   r   r   r   r  ctxs    `          r)   r   r   w  sW    c y%) 	
 
 
 	
 c
 K''$$&&*HHH#y009,,====+<===== - 9&)- $	    y 
 
 
 	
 cY	222c
 9999'899999 	9&)- $	    IIII'HIIIII 	96 %   
 AAAA'@AAAAA 	9. $    *%:: 	9. $    y"
 
 
 	

 cy, 
 
 
 	
 c <<<<';<<<<< 	9)    )x88 		 ? E E>OW&(9::UWC92). $!    y%%) 	
 
 
 	
 cz4U')%
 
 
 	
 j   EEEE(DEEEEE		!! &? ? ? 9+ $    IIII'HIIIII 	9+ %   
 BBBB'ABBBBB 	9/ $   
 y4EEEEj  
 IIII'HIIIII 	9+ %   
 BBBB'ABBBBB 	9/ $   
 y2dCCCC cy/4@@@@ kCy' 
 
 
 	
 kCy4EEEE4r(   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 V  	d S r?   r'   rP   s     r)   rS   z _classify_402.<locals>.<genexpr>v  '      HHQ!y.HHHHHHr(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z _classify_402.<locals>.<genexpr>w  s'      VV!qI~VVVVVVr(   Tr   F)rV   _USAGE_LIMIT_PATTERNS_USAGE_LIMIT_TRANSIENT_SIGNALSr   r   r   )rM   r   has_usage_limithas_transient_signals   `   r)   r  r  n  s     HHHH2GHHHHHOVVVV7UVVVVV 
/ 
y%%) 	
 
 
 	
 9!%	   r(   c          	     H	    t           fdt          D                       r |t          j        d          S t           fdt          D                       r |t          j        d          S |pd                                }	|	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                       s|	dk    r5t                              d||             |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t3                               S d}
t5          |t6                    r{|                    di           }t5          |t6                    rHt;          |                    d          pd                                                                          }
|
sHt;          |                    d          pd                                                                          }
|
sHt;          |                    d          pd                                                                          }
|
sr|                    d          }t5          |t6                    rHt;          |                    d          pd                                                                          }
t?          |
          dk     p|
d v }||d!z  k    p|d"k    o|d#k    p|d$k    }|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 V  	d S r?   r'   rP   s     r)   rS   z _classify_400.<locals>.<genexpr>  '      
E
Ea1	>
E
E
E
E
E
Er(   Tr   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z _classify_400.<locals>.<genexpr>  r   r(   r2   r   zencrypted content for itemzcould not be verifiedz0could not decrypt the provided encrypted_contentFr   c              3  ,   K   | ]}|d k    |v V  dS )rw   Nr'   rP   s     r)   rS   z _classify_400.<locals>.<genexpr>  s>       - -q+++ N++++- -r(   >   rx   ry   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z _classify_400.<locals>.<genexpr>  s'      CCqANCCCCCCr(   rv   u%  Malformed message array 400 (invalid request body) classified as format_error, NOT context overflow — failing fast + falling back instead of entering the compression loop. This usually means an empty-content assistant stub is in the transcript; num_messages=%s approx_tokens=%s. error=%.200sc              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z _classify_400.<locals>.<genexpr>  r&  r(   r   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z _classify_400.<locals>.<genexpr>  '      
>
>a1	>
>
>
>
>
>
>r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z _classify_400.<locals>.<genexpr>  r&  r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z _classify_400.<locals>.<genexpr>  r   r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z _classify_400.<locals>.<genexpr>  '      
8
8a1	>
8
8
8
8
8
8r(   r   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z _classify_400.<locals>.<genexpr>%  '      
5
5a1	>
5
5
5
5
5
5r(   r  r   r4   errorMessage	errorArgsr,      >   r2   r   g?r   i8 P   ) rV   !_MULTIMODAL_TOOL_CONTENT_PATTERNSr   r   _IMAGE_TOO_LARGE_PATTERNSr   r   r   r  r   _INVALID_MESSAGE_BODY_PATTERNSr   warningr  r   r  r   r  r   r  r   _RATE_LIMIT_PATTERNSr   r  r   rX   r   rG   rE   r3   rq   len)rM   r   r   r0   r1   r   r   r   r   error_code_lowererr_body_msgerr_obj_args
is_genericr   s   `              r)   r  r    s   * 
E
E
E
E#D
E
E
EEE 
y>
 
 
 	
 
=
=
=
=#<
=
=
=== 
y*
 
 
 	
 #(b//11777&)33(I55'944=JJy4!
 
 
 	
0 	 - - - -$@ - - - 	- 	-	
 MMMy' 
 
 
 	
  	CCCC$BCCCCC
555-
 -	
 	
 	
 y' 
 
 
 	
 
E
E
E
E#D
E
E
EEE 
y'!
 
 
 	
 
>
>
>
>#=
>
>
>>> 
y+ 
 
 
 	
 
E
E
E
E#D
E
E
EEE 
y2!
 
 
 	

 
=
=
=
=#<
=
=
=== 
y* 
 
 
 	
 
8
8
8
8#7
8
8
888 
y%%) 	
 
 
 	
 
5
5
5
5#4
5
5
555 

y"%)  5Y??	
 	
 	
 		
 L$ N((7B''gt$$ 	Mw{{955;<<BBDDJJLLL 	Jtxx	228b99??AAGGIIL  	Otxx77=2>>DDFFLLNNL 	NHH[))E%&& N"599X#6#6#<"==CCEEKKMM\""R'H<=+HJ ~33 & Qme&;&P|b?P   
h 
y+ 
 
 
 	
 9#   r(   c                   |                                  }|t          k    rd|v r |t          j        dd          S |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 dS )z:Classify by structured error codes from the response body.zrequest validation failed:FTr   >   r^   r_   rate_limit_exceeded)r9   r;   r   >   invalid_modelr   model_not_available>   max_tokens_exceededcontext_length_exceededr   r   N)
r   #PROVIDER_STREAM_NON_JSON_ERROR_CODEr   r   r   _BILLING_ERROR_CODESr   r   r   r   )r   rM   r   
code_lowers       r)   r   r   `  s^    !!##J 	999(I55 y' 
 
 
 	
 OOOy%%)
 
 
 	
 )))y"%) 	
 
 
 	
 PPPy* 
 
 
 	
 GGGy+ 
 
 
 	
 000y4!
 
 
 	
 4r(   r   c          	         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                       }|rTt           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t                               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t2          D                       r |t          j        d
d          S t           fdt6          D                       r |t          j        d          S t           fdt:          D                       r |t          j        d          S dS )zJClassify based on error message patterns when no status code is available.c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z'_classify_by_message.<locals>.<genexpr>  s'      
?
?a1	>
?
?
?
?
?
?r(   Tr   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z'_classify_by_message.<locals>.<genexpr>  r&  r(   r   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z'_classify_by_message.<locals>.<genexpr>  r   r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z'_classify_by_message.<locals>.<genexpr>  r  r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z'_classify_by_message.<locals>.<genexpr>  s'      "Z"Za1	>"Z"Z"Z"Z"Z"Zr(   r   Fc              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z'_classify_by_message.<locals>.<genexpr>  r0  r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z'_classify_by_message.<locals>.<genexpr>  r2  r(   r  c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z'_classify_by_message.<locals>.<genexpr>  r0  r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z'_classify_by_message.<locals>.<genexpr>  r&  r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z'_classify_by_message.<locals>.<genexpr>  r,  r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z'_classify_by_message.<locals>.<genexpr>	  s'      
2
2a1	>
2
2
2
2
2
2r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z'_classify_by_message.<locals>.<genexpr>  r&  r(   r   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z'_classify_by_message.<locals>.<genexpr>  r   r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z'_classify_by_message.<locals>.<genexpr>'  r   r(   c              3      K   | ]}|v V  	d S r?   r'   rP   s     r)   rS   z'_classify_by_message.<locals>.<genexpr>1  rT   r(   N)rV   _PAYLOAD_TOO_LARGE_PATTERNSr   r   r7  r   r8  r   r   r!  r   r   r  r   r  rX   r;  r  r   r  r   _AUTH_PATTERNSr   r  r   r  r   _TIMEOUT_MESSAGE_PATTERNSr   _CONNECTION_MESSAGE_PATTERNS)rM   r   r   r   r   r"  r#  s   `      r)   r   r     s    
?
?
?
?#>
?
?
??? 
y, 
 
 
 	
 
E
E
E
E#D
E
E
EEE 
y>
 
 
 	
 
=
=
=
=#<
=
=
=== 
y*
 
 
 	
 HHHH2GHHHHHO 
""Z"Z"Z"Z;Y"Z"Z"ZZZ 	9))- $	    y"%) 	
 
 
 	
 
8
8
8
8#7
8
8
888 
y%
 
 
 	
 
5
5
5
5#4
5
5
555 

y"%)  5Y??	
 	
 	
 		
 
8
8
8
8#7
8
8
888 
y%%) 	
 
 
 	
 
E
E
E
E#D
E
E
EEE 
y'!
 
 
 	
 
>
>
>
>#=
>
>
>>> 
y+ 
 
 
 	
 
2
2
2
2>
2
2
222 
y%) 	
 
 
 	
 
E
E
E
E#D
E
E
EEE 
y2!
 
 
 	
 
=
=
=
=#<
=
=
=== 
y* 
 
 
 	
 
=
=
=
=#<
=
=
=== Ay/4@@@@ 
@
@
@
@#?
@
@
@@@ Ay/4@@@@4r(   r-   c                N   | }t          d          D ]}t          |dd          }t          |t                    r|c S t          |dd          }t          |t                    rd|cxk    rdk     rn n|c S t          |dd          pt          |dd          }|||u r n|}dS )	z?Walk the error and its cause chain to find an HTTP status code.   r.   Nstatusd   r  	__cause____context__)rangegetattrr   r   )r   current_codecauses        r)   r   r   9  s    G1XX  wt44dC   	KKKw$//dC   	SD%6%6%6%63%6%6%6%6%6KKKd33\wwW[7\7\=EW,,E4r(   c                ~   | }t          d          D ]}t          |dd          }t          |t                    r|c S t          |dd          }|?	 |                                }t          |t                    r|c S n# t
          $ r Y nw xY wt          |dd          pt          |dd          }|||u r n|}i S )zKExtract the structured error body from an SDK exception or its cause chain.r`  r   Nresponserc  rd  )re  rf  r   rG   r   rs   )r   rg  rh  r   rl  	json_bodyrj  s          r)   r   r   L  s    G1XX  w--dD!! 	KKK7J55$MMOO	i.. %$$$$%   d33\wwW[7\7\=EW,,EIs   *B  
BBc                   | sdS dd}|                      di           }t          |t                    r|                     d          p|                     d          pd}t          |t                    r@|                                r,|                                dk    r|                                S |                     d	          }t          |t                    rj|                                                    d
          rCddl}	 |                    |          }n# |j        t          f$ r d}Y nw xY w ||          }|r|S |                      d          p+|                      d          p|                      d          pd}t          |t          t          f          r+t          |                                          }|r|dk    r|S dS )z4Extract an error code string from the response body.r2   r=   r3   c                r   t          | t                    sdS |                     di           }t          |t                    r|                    d          p|                    d          pd}t          |t                    r@|                                r,|                                dk    r|                                S |                     d          p|                     d          pd}t          |t          t
          f          r+t          |                                          }|r|dk    r|S dS )zAExtract a code/type from a nested error payload dict (defensive).r2   r   ri  r   400r   )r   rG   rE   r3   rq   r   )payloadpayload_errornestedri  texts        r)   _code_from_payloadz/_extract_error_code.<locals>._code_from_payloadh  s   '4(( 	2GR00mT** 	&"&&v..Q-2C2CF2K2KQrF&#&& &6<<>> &fllnnPU>U>U||~~%{{6""Egkk,&?&?E2dS#J'' 	t99??$$D rr(   r   ri  r   rp  r4   {r   Nr   	errorCode)r=   r3   )rE   r   rG   r3   rq   
startswithr   r   r   r   r   )	r   ru  	error_objri  r4   r   innernested_codert  s	            r)   r   r   c  s    r     "%%I)T"" #}}V$$C	f(=(=CdC   	 TZZ\\ 	 djjlle6K6K::<<
 --	**gs## 	#(B(B3(G(G 	#KKK

7++()4   ,,U33K #"" 88FTtxx55T+9N9NTRTD$c
## 4yy   	DEMMK2s   D" "D87D8c                   |r|                     di           }t          |t                    r[|                     dd          }t          |t                    r0|                                r|                                dd         S |                     dd          }t          |t                    r0|                                r|                                dd         S |                     dd          }t          |t                    r0|                                r|                                dd         S |                     d          }t          |t                    r[|                     dd          }t          |t                    r0|                                r|                                dd         S t          |           dd         S )	z+Extract the most informative error message.r   r4   r2   Nr  r3  r4  r,   )rE   r   rG   r3   rq   )r   r   ry  msgargsr,   s         r)   r   r     s     ,HHWb))	i&& 	)--	2..C#s## )		 )yy{{4C4((hhy"%%c3 	%CIIKK 	%99;;tt$$ hh~r**c3 	%CIIKK 	%99;;tt$$xx$$dD!! 	,XXh++F&#&& ,6<<>> ,||~~dsd++u::dsdr(   r   c                   t          | t                    sdS |pd                                                                }|                     d          }t          |t                    sdS t          |                    d          pd                                                                          }|dk    rdS |dk    rdS |                    d          }t          |t                    r
d	|v sd
|v rdS dS )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.
    Fr2   r   r4   zprovider returned error
openrouterTr   r   provider_name)r   rG   rq   r   rE   r3   )r   r0   r   err	outer_msgr   s         r)   r  r    s     dD!! un"++--3355N
((7

Cc4   uCGGI&&,"--3355;;==I---u %%twwz""H(D!! _88t5r(   r/   c                   t          | t                    sdS |                     d          }t          |t                    sdS |                    d          }t          |t                    sdS |                    d          }t          |t                    r(|                                r|                                S dS )zCPull the upstream provider name out of OpenRouter's error metadata.Nr   r   r  )r   rG   rE   r3   rq   )r   r  r   rt   s       r)   r  r    s    dD!! t
((7

Cc4   twwz""Hh%% t<<((D$  zz||4r(   )rM   r3   r=   r6   )r1   r3   r0   r3   r=   r8   )r   rs   r0   r3   r1   r3   r   r   r   r   r   r   r=   r+   )r.   r   rM   r3   r   r3   r   rG   r0   r3   r1   r3   r   r   r   r   r   r   r=   r   )rM   r3   r=   r+   )rM   r3   r   r3   r   rG   r0   r3   r1   r3   r   r   r   r   r   r   r=   r+   )r   r3   rM   r3   r=   r   )
rM   r3   r   r3   r   r   r   r   r=   r   )r   rs   r=   r-   )r   rs   r=   rG   )r   rG   r=   r3   )r   rs   r   rG   r=   r3   )r   r   r0   r3   r=   r8   )r   r   r=   r/   )=r&   
__future__r   enumloggingdataclassesr   r   typingr   r   r   	getLoggerr#   r   rH  Enumr   r+   r  rW   rX   r  	frozensetrI  r;  r  r   r!  r[  r8  r7  r  r  ru   r   r9  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(   r)   <module>r     sq  	 	 # " " " " "   ( ( ( ( ( ( ( ( & & & & & & & & & &		8	$	$ 'F #
0 0 0 0 0TY 0 0 0j B B B B B B B BF   D  7     "H 
 !y&"
" 
 
    H       	" 	" 	" 
 
 
 "
 
 
 .% % % ! , , , ^   *   X .  ""+0 " 6      4% % % !.$ $ $  >    % % % !   2      , # $ $ $   4   ,	 	 	 6   0  j; j; j; j; j; j;r t t t t t tn   L P P P P P Pj8 8 8 8zW W W Wx   &   ./ / / /d   4   <     r(   