Ë
    áß²j¡A ã                  óB  — U 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m	Z	m
Z
 ddlmZmZmZmZmZmZ  ej$                  e«      ZdZdZ G d„ d	ej.                  «      Ze	 G d
„ d«      «       ZdZdddddddddddddddddddd ge¢d!‘­Zd"Zd#Z edd$d%d&d'dd(d)d*ed+d,d-d.d/h«      Zd0Z d1Z!d2Z"d3Z#d4Z$d5Z%d6Z&d7Z'd8Z( eh d9£«      Z)d:Z*d;Z+d<Z,d=Z-d>d?d@dAdBdCe-fZ.dDZ/dEZ0dFZ1dGdHiZ2dIe3dJ<   dKZ4dLZ5dMZ6dNZ7dOZ8dPZ9dQZ:dRZ;dSZ< eh dT£«      Z=dUZ>dVZ?dWZ@dXZAeeBef   ZCd¿dY„ZDdZdZd[œZEd\dZd]œZFeZG eDeGj�                  fd^d\ieE¤ŽZI eDeGj”                  fi eE¤ŽZK eDeGj˜                  fd^d\ieE¤ŽZM eDeGj˜                  fi eF¤ŽZN eDeGjž                  fi eF¤ŽZP eDeGj¢                  fi eF¤ŽZR eDeGj¦                  fi eF¤ŽZT eDeGjª                  fd^d\ieE¤ŽZV eDeGj®                  fi eF¤ŽZX eDeGj²                  fi eF¤ŽZZ eDeGj¶                  fi eF¤ŽZ\ eDeGjº                  dZ¬_«      Z^ eDeGj¾                  dZ¬_«      Z` eaeDeGjÄ                  eGjÆ                  eGjÈ                  eGjÊ                  f«      \  ZfZgZhZi eDeGjÔ                  «       eDeGjÖ                  «      cZlZm eDeGjÜ                  «       eDeGjÞ                  «      cZpZq eDeGjä                  d\d\¬`«      Zs eDeGjè                  fi eF¤ŽZu eDeGj®                  d\d\¬]«      ZvdaZwdbZx ejò                  dc«      Zz ejò                  dd«      Z{deZ|dÀdf„Z}dÀdg„Z~dÁdh„ZdÂdi„Z€e'epfe&emfe%elffZ�e:egfe(effe*e^ffZ‚eeIfe7eZfe,ePffZƒe‚e7eZfe,ePfe eKfeeffz   Z„e(effe$e`fe/euffe�z   Z…e!effeefe eKfe:egfe*e^fe9eMfe7eZfe,ePfe;ehfe<ehff
Z†i e‡�j                  dj eDeGj”                  dZ¬k«      «      ¥e‡�j                  eeI«      ¥e‡�j                  dleP«      ¥e‡�j                  dme^«      ¥e‡�j                  e)ef«      ¥dneqi¥Z‰doe3dp<   dqdrdrdrdrdrdsœZŠdtegiefehegduœegeKdvœdwœZ‹dxe3dy<   dzd{hZŒeŒd|hz  Z� eŽd}„ e1D «       «      Z�e	 G d~„ d«      «       Z�dÃd€„Z‘dÃd�„Z’d‚Z“ eej”                  e�j(                  ejÄ                  ejº                  ej¾                  e�j*                  e�j,                  h«      Z—e8 eŽdƒ„ eD «       «      z   Z˜dÃd„„Z™dÃd…„ZšdÃd†„Z›dÃd‡„ZœdÃdˆ„Z�dÃd‰„ZždÃdŠ„ZŸe‘e’ešeŸe›eœe�ežfZ d‹e3dŒ<   d�d�ddŽdd�dd�œ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dÄd�„Z¡dÅd‘„Z¢ ed’h«      Z£dÆd“„Z¤dÆd”„Z¥dÆd•„Z¦dÆd–„Z§dÇd—„Z¨dÈd˜„Z©dÉd™„ZªdÆdš„Z«dÆd›„Z¬e«dœ„ d�„ e¤e¥dž„ dŸ„ d „ e¦e§e§d¡„ d¢„ d£œZ­d¤e3d¥<   d¦Z®d§Z¯dÊd¨„Z°dËd©„Z±dÌdª„Z²dÍd«„Z³d¬Z´d­ZµdÎd®„Z¶dÏd¯„Z·dÐd°„Z¸dÑd±„Z¹dÒd²„ZºdÓd³„Z»dÔd´„Z¼dÕdµ„Z½dÖd¶„Z¾d×d·„Z¿dØd¸„ZÀdÙd¹„ZÁdÚdº„ZÂdÛd»„ZÃdÜd¼„ZÄdÝd½„ZÅdÞd¾„ZÆy)ßa   API error classification for smart failover and recovery.

A priority-ordered pipeline maps an API exception to a ``ClassifiedError``
whose recovery hints (retry, rotate credential, fallback, compress, abort) the
retry loop in run_agent.py consults instead of re-matching strings itself.
é    )ÚannotationsN)Ú	dataclassÚfield)ÚAnyÚCallableÚDictÚIteratorÚOptionalÚSequenceÚprovider_stream_non_json_dataÚprovider_stream_empty_framec                  ó„   — 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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Úupstream_blockedÚ
overloadedÚserver_errorÚtimeoutÚssl_cert_verificationÚcontext_overflowÚpayload_too_largeÚimage_too_largeÚimage_corruptÚmodel_not_foundÚprovider_policy_blockedÚcontent_policy_blockedÚmodel_entitlementÚincomplete_responseÚformat_errorÚrole_alternationÚinvalid_encrypted_contentÚ#multimodal_tool_content_unsupportedÚreasoning_mandatoryÚ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&   r'   r(   r)   r*   r+   r,   © ó    ú;/home/ubuntu/.hermes/hermes-agent/agent/error_classifier.pyr   r   "   s©   „ ÙBØ€DØ%€NØ€GØ€JØ/ÐØ)ÐØ€JØ!€LØ€GØ3ÐØ)ÐØ+ÐØ'€OØ#€MØ'€OØ7ÐØ5ÐØ+ÐØ/ÐØ!€LØ)ÐØ ;ÐØ*OÐ'Ø/Ðð .ÐØ+ÐØ(KÐ%Ø ;ÐØ�Gr2   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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)r6   r   r   r   ©Úselfs    r3   Úis_authzClassifiedError.is_authV   s"   € à�{‰{œ~×2Ñ2´N×4QÑ4QÐRÐRÐRr2   c                óJ   — t        | j                  j                  d«      «      S )zDTrue when a ``billing`` verdict rests on an ambiguous body (#82154).Úbilling_unverified)rA   r@   ÚgetrH   s    r3   rL   z"ClassifiedError.billing_unverifiedZ   s!   € ô �D×&Ñ&×*Ñ*Ð+?Ó@ÓAÐAr2   )ÚreturnrA   )r-   r.   r/   r0   Ú__annotations__r8   r:   r;   r>   r   Údictr@   rB   rC   rD   rE   ÚpropertyrJ   rL   r1   r2   r3   r5   r5   E   s—   … áHàÓØ!%€K�Ó%Ø"€HˆmÓ"Ø€Eˆ=ÓØ€GˆSÓÙ$)¸$Ô$?€M�>Ó?ð €IˆtÓØ!€O�TÓ!Ø%*Ð˜dÓ*Ø!€O�TÓ!àòSó ðSð òBó ñBr2   r5   )Ú model_not_supported_on_free_tierznot available on the free tierz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_depletedzbudget limit exceededzhard billing limit)rT   z$personal-team-blocked:spending-limitÚbilling_not_activeÚpayment_requiredÚinsufficient_creditsÚno_usable_creditsrR   Úmember_spend_cap_exceededÚterminal_quota_exhaustedÚcredit_balance_exhaustedÚ!organization_spend_limit_exceededÚ!organization_usage_limit_exceededÚproject_spend_limit_exceededÚ#insufficient_credits_for_paid_model)z
rate limitr   ztoo many requestsÚ	throttledzrequests per minuteztokens per minutezrequests per dayztry again inzplease retry afterzresource exhaustedÚresource_exhaustedzresource-exhaustedÚresourceexhaustedz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server overloadÚserver_overloadzservice overloadedzservice is overloadedzupstream overloadedzcurrently overloadedzQupstream model provider is temporarily unavailable. please try again in a moment.zat capacityzover capacity)zusage limitÚquotazlimit exceededúkey limit exceeded)z	try againÚretryz	resets atzreset inz	resets inzreset afterzavailable inÚwaitzrequests remainingÚperiodicÚwindowz
per minutez
per second)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: 8000zmedia exceedszmedia too largezpatches after processingzmake sure your payload is belowz(streamreadconstraints.getmaxstringlength)zinvalid png imagezinvalid jpeg imagez1base64 string of provided image cannot be decodedzIdownloaded response does not contain a valid jpg, png, webp, or ico image)
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 stringztool.content.strzinput should be a valid stringÚ'chatcompletionrequesttoolmessagecontent)zmemory guardzmemory limit exceededÚmemory_guard_tierzdynamic ceilingzmemory ceilingzavailable memoryzout of memoryzinsufficient memoryzprefill would requirezpredicted peak wouldzprefill safety capÚ	metal_cap>   Úprefill_memory_abortedÚprefill_memory_exceededÚomlx_prefill_memory_exceeded)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 allowedrw   zmax input tokenzinput tokenz*exceeds the maximum number of input tokenszmaximum allowed input lengthz>model is not supported when using codex with a chatgpt account)	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 usez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roles must alternatezrole must alternatezmust alternate betweenzconsecutive user messagesz'consecutive messages with the same rolez%consecutive messages of the same rolezsame role in a rowzmultiple user messages in a rowz$adjacent messages with the same role)	zinvalid tool call argumentszinvalid tool_call argumentszinvalid tool_calls argumentszinvalid function call argumentszinvalid function_call argumentsztool call arguments are invalidztool_call arguments are invalidz#function call arguments are invalidz#function_call arguments are invalid)úunknown parameterúunsupported parameterúunrecognized request argumentÚinvalid_request_errorÚunknown_parameterÚunsupported_parameterÚprompt_cache_retention)ÚmetaÚmuseÚmslz	model-apiÚbedrockÚmantlezDict[str, tuple]Ú_SERVER_INJECTED_PARAM_SENDERS)únot supportedÚunsupportedr,   Úunrecognized)Ú	signaturezcannot be modifiedzmust remain as they were)z.'types.SimpleNamespace' object is not iterablez7'types.SimpleNamespace' object has no attribute 'index')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_sensitivezcontent exists risk)zinvalid api keyÚinvalid_api_keyÚgateway_auth_failedÚauthenticationÚunauthorizedÚ	forbiddenzinvalid tokenztoken expiredztoken revokedzaccess deniedz&failed to extract accountid from token)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:)
zyour request was blockedzrequest blockedzsorry, you have been blockedz)enable javascript and cookies to continuezcdn-cgi/challenge-platformzcf-browser-verificationzchallenge-error-textÚ__cf_chlzcf-error-detailsz attention required! | cloudflarec                ó   — d| i|¥S )Nr6   r1   )r6   Úhintss     r3   Ú_vr±   ¿  s   € Ø�fÐ& Ð&Ð&r2   T)rD   rE   F)rB   rE   rB   ©rC   )rC   rE   zreasoning is mandatory)r{   r   r‡   zdoes not supportzdoesn't supportzis deprecated for this modelrz   r|   zunrecognized parameterzinvalid parameterzextra inputs are not permittedzinvalid option: expected one ofz¢(?<![\w\-/])(?:reasoning_effort|thinking_config|thinking_budget|enable_thinking|thinkingconfig|thinkingbudget|reasoning|thinking|think)(?![\w\-/])(?!\s+models?\b)z~['"]param['"]\s*:\s*['"](?:reasoning(?:[._]effort)?|thinking(?:_config|_budget)?|enable_thinking)['"]|invalid_reasoning_effort)Ú	mandatoryzcannot be disabledzcan't be disabledzmust be enabledzis requiredzalways enabledzcannot be turned offc                óî   ‡— | xs dj                  «       }t        j                  |«      }|€y|t        d|j	                  «       dz
  «      |j                  «       dz    Št        ˆfd„t        D «       «      S )aÈ  Provider 400 saying the model's reasoning cannot be switched OFF ("Reasoning is mandatory for
    this endpoint and cannot be disabled", the Nous Portal on gpt-6-astra). The opposite of
    ``is_reasoning_field_rejection``: the field is understood, the *disable* is refused, so the right
    reaction is to step the effort up to the lowest level rather than drop the field (a dropped field
    also works, but tells the caller nothing about the next call).r<   Fr   é0   é`   c              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   )Ú.0ÚmÚnears     €r3   ú	<genexpr>z2is_reasoning_required_rejection.<locals>.<genexpr>  s   øè ø€ Ò>˜Qˆq�DŒyÑ>ùó   ƒ)ÚlowerÚ_REASONING_FIELD_TOKENÚsearchÚmaxÚstartÚendÚanyÚ_REASONING_REQUIRED_MARKERS)Ú	error_msgÚmsgÚtokenrº   s      @r3   Úis_reasoning_required_rejectionrÈ     sj   ø€ ð Š?˜×
!Ñ
!Ó
#€CÜ"×)Ñ)¨#Ó.€EØ€}ØØŒs�1�e—k‘k“m bÑ(Ó)¨%¯)©)«+¸Ñ*:Ð;€DÜÓ>Ô"=Ô>Ó>Ð>r2   c                ó&  ‡— | xs dj                  «       Št        j                  ‰«      ryt        j                  ‰«      }|€y‰t	        d|j                  «       dz
  «      |j                  «       dz    }d|v xs t        ˆfd„t        D «       «      S )u�  Provider 400 rejecting a reasoning wire control by name (``reasoning_effort``, ``reasoning``,
    ``thinking``/``think``): the field token plus either a generic unsupported marker ("Unrecognized
    request argument supplied: reasoning_effort", #112781) or a standalone "unsupported" next to the
    field in either word order ("unsupported reasoning_effort"; "reasoning_effort 'none' unsupported;
    use minimal|low|medium|high|xhigh", #114460). The route default is the right answer for such a
    model, so both the main loop and the auxiliary ladder retry once without the disable. A body
    whose structured ``param``/code names the reasoning field (``'param': 'reasoning.effort'``,
    ``invalid_reasoning_effort``, #100536) is a rejection whatever the message says â€” even none.

    Known trade-off: a 400 about a thinking *state* ("Function calling is not supported when
    thinking is enabled") also matches â€” the marker sits right next to the token, so no proximity
    rule separates it from the forward wordings. Cost is one dropped-disable retry before the
    spent path takes the fallback chain; the auxiliary ladder already treated it this way.r<   TFr   é    rˆ   c              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   )r¸   r¹   rÆ   s     €r3   r»   z/is_reasoning_field_rejection.<locals>.<genexpr>1  s   øè ø€ Ò'T°Q¨¨S¬Ñ'Tùr¼   )	r½   Ú_REASONING_PARAM_REJECTIONr¿   r¾   rÀ   rÁ   rÂ   rÃ   ÚUNSUPPORTED_PARAM_MARKERS)rÅ   rÇ   rº   rÆ   s      @r3   Úis_reasoning_field_rejectionrÎ     s…   ø€ ð Š?˜×
!Ñ
!Ó
#€CÜ!×(Ñ(¨Ô-ØÜ"×)Ñ)¨#Ó.€EØ€}ØØŒs�1�e—k‘k“m bÑ(Ó)¨%¯)©)«+¸Ñ*:Ð;€DØ˜DÐ ÒT¤CÓ'TÔ:SÔ'TÓ$TÐTr2   c                óZ   ‡ — i }t        ˆ fd„t        D «       «      rdddœ}i t        ¥d|i¥S )zEBilling verdict carrying the #82154 ambiguity marker when applicable.c              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   ©r¸   ÚprÅ   s     €r3   r»   z!_billing_hints.<locals>.<genexpr>7  s   øè ø€ Ò
@˜aˆ1�	Œ>Ñ
@ùr¼   T)rL   Úpossible_content_filterr@   )rÃ   Ú_UNVERIFIED_BILLING_PATTERNSÚ
_V_BILLING)rÅ   Úctxs   ` r3   Ú_billing_hintsr×   4  s3   ø€ à€CÜ
Ó
@Ô#?Ô
@Ô@Ø%)ÀdÑKˆØ/ŒjÐ/˜/¨3Ñ/Ð/r2   c                ót   ‡ — |D ]2  \  }}t        ˆ fd„|D «       «      sŒt        |«      r
 |‰ «      c S |c S  y)z@Verdict of the first rule whose pattern list hits ``error_msg``.c              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   rÑ   s     €r3   r»   z_first_match.<locals>.<genexpr>?  s   øè ø€ Ò0 !ˆq�IŒ~Ñ0ùr¼   N)rÃ   Úcallable)rÅ   ÚrulesÚpatternsÚverdicts   `   r3   Ú_first_matchrÞ   <  sC   ø€ à"ò HÑˆ�'ÜÓ0 xÔ0Õ0Ü)1°'Ô):‘7˜9Ó%ÒGÀÒGðHð r2   )rb   ra   Úrate_limit_exceeded)rD   )r   Úmodel_not_availableÚinvalid_model)Úcontext_length_exceededÚmax_tokens_exceededr%   zDict[str, Verdict]Ú_ERROR_CODE_VERDICTSÚopenaiÚgemini)úopenai-codexÚgooglezgoogle-geminizgoogle-ai-studioÚvertexzgoogle-vertexr   )ÚunavailableÚdeadline_exceededÚinternal)Ú	api_errorÚrate_limit_error)rå   ræ   Ú	anthropiczDict[str, Dict[str, Verdict]]Ú_PROVIDER_CODE_VERDICTSr~   r   r}   c              #  ó,   K  — | ]  }|d k7  sŒ	|–— Œ y­w)r}   Nr1   ©r¸   rÒ   s     r3   r»   r»   �  s   è ø€ Ò i qÈAÐQhÓLh¤Ñ iùs   ‚
�c                  ó˜   — e Zd ZU dZded<   ded<   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d„Zdd„Zy)Ú_Ctxz<Everything the classifier stages need about one failed call.Ú	ExceptionÚerrorr7   r8   rP   Úbodyr=   rÆ   r:   r;   ÚintÚapprox_tokensÚcontext_lengthÚnum_messagesr<   Úbase_urlFrA   Ú	anonymousc                óÂ  — t        | j                  «      j                  | _        t	        | j
                  «      | _        | j                  j                  «       | _        t        | j                  t        i «      | _        | j                  xs dj                  «       j                  «       | _        | j                  xs dj                  «       j                  «       | _        y ©Nr<   )Útyperö   r-   Ú
error_typeÚ_extract_error_coder÷   Ú
error_coder½   ÚcodeÚ_from_cause_chainÚ_headers_ofÚheadersr:   ÚstripÚprovider_slugr;   Ú
model_slugrH   s    r3   Ú__post_init__z_Ctx.__post_init__¢  s•   € Ü˜tŸz™zÓ*×3Ñ3ˆŒÜ-¨d¯i©iÓ8ˆŒØ—O‘O×)Ñ)Ó+ˆŒ	Ü(¨¯©´[À"ÓEˆŒØ"Ÿm™mÒ1¨r×8Ñ8Ó:×@Ñ@ÓBˆÔØŸ:™:Ò+¨×2Ñ2Ó4×:Ñ:Ó<ˆ�r2   c                ó    — | j                   | j                  |z  kD  xs1 | j                  dk  xr  | j                   |kD  xs | j                  |kD  S )z;Absolute thresholds only proxy for smaller context windows.i è )rù   rú   rû   )rI   ÚfracÚtokensÚmessagess       r3   Úlarge_sessionz_Ctx.large_sessionª  sT   € à×!Ñ! D×$7Ñ$7¸$Ñ$>Ñ>ò 
Ø×Ñ 6Ñ)Òk¨t×/AÑ/AÀFÑ/JÒ/jÈd×N_ÑN_ÐbjÑNjð	
r2   N)rN   ÚNone)r  Úfloatr  rø   r  rø   rN   rA   )	r-   r.   r/   r0   rO   rü   rý   r  r  r1   r2   r3   rô   rô   ’  sU   … áFàÓØÓØ
ƒJØ	ƒHØƒMØƒJØÓØÓØÓØ€HˆcÓØ€IˆtÓó=ô
r2   rô   c                óä  — 	 ddl m}  || j                  | j                  | j                  | j
                  | j                  | j                  | j                  | j                  | j                  | j                  | j                  ¬«      }|�9t        j!                  d|d   j"                  | j                  | j                  «       |S # t        $ r }t        j                  d|«       Y d}~yd}~ww xY w)z×First valid plugin classification (runs before the built-in pipeline so a
    provider plugin can add or correct verdicts). invoke_hook isolates callback
    failures; this guard only covers import/dispatch failure.r   )Úget_plugin_error_classification)r:   r;   r8   r  r  Úerror_messageÚ
error_bodyrö   rù   rú   rû   z+Plugin error classification unavailable: %sNz@API error classified by plugin hook: %s (provider=%s, status=%s)r6   )Úhermes_cli.pluginsr  r:   r;   r8   r  r  rÆ   r÷   rö   rù   rú   rû   rõ   ÚloggerÚdebugÚinfoÚvalue)Úcr  rÝ   Úexcs       r3   Ú_plugin_verdictr  ±  s¿   € ð	ÝFÙ1Ø—Z‘Z q§w¡w¸A¿M¹MÐVW×VbÑVbØ—|‘|°1·5±5ÀQÇVÁVÐST×SZÑSZØŸ/™/¸!×:JÑ:JÐYZ×YgÑYgô
ˆð ÐÜ�‰ÐVØ˜HÑ%×+Ñ+¨Q¯Z©Z¸¿¹ô	Hà€Nøô ò Ü�‰ÐBÀCÔHÜûðús   ‚BC Ã	C/ÃC*Ã*C/c                óà  — | j                   sy	 ddlm} t         || j                   «      dd«      }t	        |«      sy || j
                  | j                  | j                  | j                  | j                  | j                  ¬«      }t        |t        «      sy|j!                  d«      }t        |t"        «      r(	 t%        |j'                  «       j)                  «       «      }t        |t$        «      syt,        D �ci c]  }||v sŒ|t/        ||   «      “Œ }}|j!                  d«      rd	|vr|t0        vrd
|d	<   t3        |fi |¤Ž}t        |j!                  d«      t        «      r|d   |d<   t        j5                  d|j6                  | j8                  | j                  «       |S # t        $ r+}t        j                  d| j                   |«       Y d}~yd}~ww xY w# t*        $ r Y yw xY wc c}w )aŒ  The current provider's own ``ProviderProfile.classify_api_error`` verdict, or None.

    A ``kind: model-provider`` plugin never enters the PluginManager hook lifecycle, so without this a
    vendor-specific body (a 403 ``quota_exhausted`` that is billing, not auth) could only be corrected by
    shipping a second plugin component. Scoped to the provider that produced the error; no name table.Nr   )Úget_provider_profileÚclassify_api_error)r8   r  r>   r÷   r;   z7Provider profile error classification failed for %s: %sr6   rE   rB   Fr@   zEAPI error classified by provider profile: %s (provider=%s, status=%s))r	  Ú	providersr   ÚgetattrrÚ   rö   r8   r  rÆ   r÷   r;   rõ   r  r  Ú
isinstancerP   rM   r=   r   r  r½   Ú
ValueErrorÚ_HINT_FLAGSrA   ÚRETRYABLE_CLIENT_REASONSr±   r  r  r:   )	r  r   ÚhookÚresultr  r6   Úkr°   rÝ   s	            r3   Ú_profile_verdictr+  Å  s¬  € ð �?Š?Øð	Ý2ÜÑ+¨A¯O©OÓ<Ð>RÐTXÓYˆÜ˜Œ~ØÙ�a—g‘g¨1¯=©=ÀQÇ\Á\Ð[\×[`Ñ[`ØŸ6™6¨¯©ô2ˆô
 �fœdÔ#ØØ�Z‰Z˜Ó!€FÜ�&œ#Ôð	Ü# F§L¡L£N×$8Ñ$8Ó$:Ó;ˆFô �fœnÔ-ØÜ)4ÖD A¸¸VºˆQ”�V˜A‘Y“ÑÐD€EÐDð
 ‡y�yÐ"Ô#¨¸5Ñ(@ÀVÔSkÑEkØ"ˆˆkÑÜ�Ñ!˜5Ñ!€GÜ�&—*‘*˜_Ó-¬tÔ4Ø#)¨/Ñ#:ˆ�Ñ Ü
‡K�KÐWØ—‘˜aŸj™j¨!¯-©-ô9à€Nøô3 ò Ü�‰ÐNÐPQ×P_ÑP_ÐadÔeÜûðûô ò 	Ùð	üò Es;   �.F% ¾A
F% Â;'G Ã;	G+ÄG+Æ%	GÆ.!GÇGÇ	G(Ç'G()rB   rC   rD   rE   c              #  ó2   K  — | ]  }|t         vsŒ|–— Œ y ­wrG   )Ú_FREE_TIER_REFUSAL_PATTERNSrò   s     r3   r»   r»   þ  s!   è ø€ ò GJØ
 AÔ-HÒ$H„AñGJùs   ‚�c                óä  ‡ — ddl m}m}m} ‰ j                  }‰ j
                  sJ‰ j                  dk(  r:|dk(  r5 ||‰ j                  «      dk(  rt        t        j                  ddddi¬	«      S y
|dk(  r~ |‰ j                  «      }|€y
d|i}|d   |v rt        t        j                  dd|¬	«      S |d   dkD  rt        j                  «       |d   z   |d<   t        t        j                  d|¬«      S t        ˆ fd„t         D «       «       } ||‰ j                  |r‰ j"                  nd
«      }|€y
d|i}|dk(  rt        t        j$                  dd|¬	«      S t        t        j                  dd|¬	«      S )uœ  The Nous inference gateway's welcome-tier (free tier) refusals, read from the structured body.

    A 429 carrying a fairshare ``reason`` is either a tier gate (``model_not_free`` /
    ``feature_not_free``: the model or feature is never served on the free tier, so retrying is
    pointless â€” abort this route and fall back) or capacity (``at_capacity`` / ``admission_closed``
    / ``rate_limited``: honour ``retry_after``, never rotate the free tier's only credential). A
    400/403 whose message names the wrong host or a dark tier is deterministic for the request.
    The parsed refusal rides ``error_context`` so the terminal copy can say what happened.
    r   )ÚWELCOME_TIER_GATE_REASONSÚparse_welcome_refusalÚwelcome_route_refusalÚnousé�  Únamed_on_welcome_hostFTÚwelcome_route)rB   rE   r@   Né­  Úwelcome_refusalr6   Úretry_afterÚreset_at©rE   r@   c              3  ó:   •K  — | ]  }|‰j                   v –— Œ y ­wrG   ©rÆ   ©r¸   rÒ   r  s     €r3   r»   z%_nous_welcome_tier.<locals>.<genexpr>#  s   øè ø€ ÒH q˜˜QŸU™Uœ
ÑHùó   ƒé“  )Úhermes_cli.anon_authr/  r0  r1  r8   rý   r:   rÆ   r±   Ú_Rr#   r÷   r   Útimer   rÃ   Ú_WELCOME_403_NAMED_PATTERNSrü   r   )	r  r/  r0  r1  ÚstatusÚrefusalrÖ   Ú	plain_403Úkinds	   `        r3   Ú_nous_welcome_tierrH    sl  ø€ ÷Qñ Qà�]‰]€FØ�;Š;ð �:‰:˜Ò F¨c¢MÑ6KÈFÐTU×TYÑTYÓ6ZÐ^uÒ6uÜ”b—o‘o°ÈØ%4Ð6MÐ$NôPð PàØ�‚}Ù'¨¯©Ó/ˆØˆ?ØØ  'Ð*ˆØ�8ÑÐ 9Ñ9Ü”b×(Ñ(°EÈ4Ð_bÔcÐcØ�=Ñ! AÒ%Ü"Ÿi™i›k¨G°MÑ,BÑBˆC�
‰OÜ”"—-‘-°ÀSÔIÐIô ÓHÔ,GÔHÓHÐH€IÙ  ¨¯©¹i°·
²
ÈTÓR€DØ€|ØØ˜DÐ
!€CØ�‚}Ü”"×#Ñ#¨uÀdÐZ]Ô^Ð^ÜŒb�o‰o¨ÀÐTWÔXÐXr2   c                óô  ‡— | j                   | j                  cŠ}t        | «      }|�|S t        ˆfd„t        D «       «      rt
        S t        | «      rt        t        j                  fi t        ¤ŽS |dk(  r| j                  dk(  sd‰v rt        S |dk(  r5d‰v r1t        ˆfd„t        D «       «      rt        t        j                  «      S |dk(  r#d‰v rd	‰v rt        t        j                  d
¬«      S |dk(  r!d‰v rd‰v rt        t        j                   «      S d‰v xs" d‰v xs d‰v xr d‰v xs d‰v xr
 d‰v xr d‰v }|dk(  r#|r!t"        ‰vrt        t        j$                  «      S d‰v sd‰v r
d‰v rt&        S y)zLHighest-priority provider-specific shapes that a status code would misroute.Nc              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   ©r¸   rÒ   rÆ   s     €r3   r»   z*_provider_special_cases.<locals>.<genexpr>5  s   øè ø€ Ò
>˜ˆ1�Œ8Ñ
>ùr¼   r3  Úthinking_signature_invalidÚthinkingc              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   rK  s     €r3   r»   z*_provider_special_cases.<locals>.<genexpr>E  s   øè ø€ Ò2^À°1¸´8Ñ2^ùr¼   r6  zextra usagezlong contextTr²   zlong context betaznot yet availablezerror parsing grammarzjson-schema-to-grammarzunable to generate parserÚtemplatezinvalid json schemazregex lookaroundr‡   z'do not have an active grok subscriptionzout of available resourcesÚgrok)rÆ   r8   rH  rÃ   Ú _CONTENT_POLICY_BLOCKED_PATTERNSÚ_V_CONTENT_BLOCKEDÚ!_is_codex_masked_replay_rejectionr±   rA  r%   Ú_ABORT_FALLBACKr  Ú_V_INVALID_ENCRYPTEDÚ_THINKING_MUTATION_WORDSr(   r)   r*   Ú_NO_USER_QUERY_SIGNALr+   Ú_V_AUTH_FALLBACK)r  rD  ÚwelcomeÚgrammar_hitrÆ   s       @r3   Ú_provider_special_casesr[  -  s¨  ø€ à—%‘%˜Ÿ™€K€CˆÜ  Ó#€GØÐØˆô Ó
>Ô=Ô
>Ô>Ü!Ð!ô )¨Ô+Ü”"×.Ñ.ÑB´/ÑBÐBð �‚}˜!Ÿ&™&Ð$@Ò@ÐD`ÐdgÑDgÜ#Ð#ð �‚}˜ sÑ*¬sÓ2^ÔE]Ô2^Ô/^Ü”"×'Ñ'Ó(Ð(à�‚}˜¨#Ñ-°.ÀCÑ2GÜ”"×&Ñ&¸Ô=Ð=à�‚}Ð,°Ñ3Ð8KÈsÑ8RÜ”"×6Ñ6Ó7Ð7ð *¨SÐ0ò aÐ4LÐPSÐ4Sò aØ# sÐ*Ò@¨z¸SÐ/@òaà
 3Ð
&Ò
_Ð+=ÀÐ+DÒ
_ÈÐ\_ÐI_ð ð �‚}™Ô)>ÀcÑ)IÜ”"×.Ñ.Ó/Ð/ð 1°CÑ7Ð<XÐ\_Ñ<_ÐdjÐnqÑdqÜÐØr2   c                óú   ‡ — ‰ j                   dk(  r3t        ˆ fd„t        D «       «      rt        t        j
                  d¬«      S ddlm} t        ‰ j                  |«      rt        t        j                  d¬«      S d S )NÚmoac              3  óL   •K  — | ]  }|t        ‰j                  «      v –— Œ y ­wrG   )r=   rö   )r¸   Úsr  s     €r3   r»   z%_moa_special_cases.<locals>.<genexpr>c  s   øè ø€ Ò'[¸a¨¬S°·±«\Ô(9Ñ'[ùs   ƒ!$F)rB   r   )ÚMoAPresetNotFoundError)r	  rÃ   Ú_MOA_ADAPTER_SHAPE_BUGSr±   rA  r#   Úagent.errorsr`  r$  rö   r   )r  r`  s   ` r3   Ú_moa_special_casesrc  `  sZ   ø€ ð 	‡�˜%Ò¤CÓ'[ÔCZÔ'[Ô$[Ü”"—/‘/¨UÔ3Ð3å3Ü6@ÀÇÁÐJ`Ô6aŒ2Œb× Ñ ¨EÔ2ÐkÐgkÐkr2   c                óH  — | j                   t        k(  rd| j                  v rt        S t        j                  | j                   «      }|€Yt        j                  | j                  | j                  «      }t        j                  |i «      j                  | j                   «      }|S )z.Structured error codes from the response body.zrequest validation failed:)	r  Ú#PROVIDER_STREAM_NON_JSON_ERROR_CODErÆ   Ú_V_FORMAT_ERRORrä   rM   Ú_PROVIDER_CODE_FAMILIESr	  rð   )r  rÝ   Úfamilys      r3   Ú_by_error_coderi  j  s   € ð 	‡v�vÔ4Ò4Ð9UÐYZ×Y^ÑY^Ñ9^ÜÐÜ"×&Ñ& q§v¡vÓ.€GØ€Ü(×,Ñ,¨Q¯_©_¸a¿o¹oÓNˆÜ)×-Ñ-¨f°bÓ9×=Ñ=¸a¿f¹fÓEˆØ€Nr2   c                óÜ   ‡ — t        ‰ j                  t        «      }|�|S t        ˆ fd„t        D «       «      }|rt        ‰ j                  t        «      S t        ‰ j                  t        «      S )zqMessage patterns when no status code settled it; status-less usage
    limits get the same disambiguation as 402.c              3  ó:   •K  — | ]  }|‰j                   v –— Œ y ­wrG   r<  r=  s     €r3   r»   z_by_message.<locals>.<genexpr>}  s   øè ø€ Ò@ Q�a˜1Ÿ5™5”jÑ@ùr>  )rÞ   rÆ   Ú_MESSAGE_HEAD_RULESrÃ   Ú_USAGE_LIMIT_PATTERNSÚ_classify_402rP   Ú_MESSAGE_TAIL_RULES)r  ÚheadÚusage_limits   `  r3   Ú_by_messagerr  w  sV   ø€ ô ˜Ÿ™Ô2Ó3€DØÐØˆÜÓ@Ô*?Ô@Ó@€KÙ)4Œ=˜Ÿ™¤Ó%Ðb¼,ÀqÇuÁuÔNaÓ:bÐbr2   c                ó  ‡— | j                   Št        ‰t        t        ft        t
        ff«      }|�|S t        ˆfd„t        D «       «      rI| j                  s=ddl	m
}  || j                  «      �t
        S | j                  ddd«      rt        S t
        S | j                  dk(  r&d	‰v r"d
‰v rt        t         j"                  fi t$        ¤ŽS | j                  t&        v xs% t)        | j*                  t,        t.        t0        f«      }|rt
        S dS )zNSSL, disconnect, circuit-breaker and transport-type heuristics, in that order.Nc              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   rK  s     €r3   r»   z _by_transport.<locals>.<genexpr>Š  s   øè ø€ Ò
9˜ˆ1�Œ8Ñ
9ùr¼   r   )Ú!get_reasoning_stale_timeout_floorg333333ã?iÀÔ éÈ   ÚRuntimeErrorzconsecutive stale attemptszaborting this call)rÆ   rÞ   Ú_SSL_CERT_VERIFY_PATTERNSÚ_V_SSL_CERTÚ_SSL_TRANSIENT_PATTERNSÚ
_V_TIMEOUTrÃ   Ú_SERVER_DISCONNECT_PATTERNSr8   Úagent.reasoning_timeoutsru  r;   r  Ú_V_CONTEXT_OVERFLOWr  r±   rA  r   rT  Ú_TRANSPORT_ERROR_TYPESr$  rö   r›   rŸ   ÚOSError)r  Ússlru  Ú	transportrÆ   s       @r3   Ú_by_transportrƒ  �  sé   ø€ à
�%‰%€Cô �sÔ7¼ÐEÔH_ÔakÐGlÐmÓ
n€CØ
€Øˆ
ä
Ó
9Ô8Ô
9Ô9À!Ç-Â-õ 	OÙ,¨Q¯W©WÓ5ÐAÜÐØ&'§o¡o°c¸6À3Ô&GÔ"ÐWÌZÐWð 	‡|�|�~Ò%Ð*FÈ#Ñ*MÐRfÐjmÑRmÜ”"—*‘*Ñ0¤Ñ0Ð0Ø—‘Ô 6Ð6Òw¼*ÀQÇWÁWÌ|Ô]lÔnuÐNvÓ:w€IÙ"Œ:Ð,¨Ð,r2   c                ó¤   — | j                   }|€yd|cxk  rdk  r	n nt        nd|cxk  rdk  r	n nt        nd}|t        v rt        |   | «      S |S )uN   HTTP status code with message-aware refinement (unlisted 4xx/5xx â†’ generic).Nr3  éô  éX  )r8   rf  Ú_V_SERVER_ERRORÚ_STATUS_HANDLERS)r  rD  Údefaults      r3   Ú
_by_statusrŠ  £  sU   € à�]‰]€FØ€~ØØ!$¨Ô!4°Õ!4�oÈSÐTZÔM`Ð]`ÕM`½/Ðfj€GØ*0Ô4DÑ*DÔ˜FÑ# AÓ&ÐQÈ'ÐQr2   z-Sequence[Callable[[_Ctx], Optional[Verdict]]]Ú_STAGESr<   i@ )r:   r;   rù   rú   rû   rü   Úapi_keyc               óÜ  ‡— ddl m} t        | «      }	|	€t        | «      j                  dk(  rd}	t        | «      }
t        | |	|
t        | |
«      |||||t        |xs d«       |||«      ¬«      Št        d„ ˆfd„t        D «       D «       t        «      }t        | |
«      }|d	   t        j                  t        j                  fv rt!        ‰«      }|r|› d
|› d�}|	|||dœ}t#        di i |¥|¥¤ŽS )a—  Classify an API error into a structured recovery recommendation (see ``_STAGES``).

    ``base_url`` (optional) is the route the call went to; the Nous welcome tier keys its
    dark-tier 403 on it because that refusal carries no distinguishing message.
    ``api_key`` identifies an anonymous request; a host or fairshare reason alone does not.
    The credential is never included in the returned context.r   )Úis_anonymous_requestÚRateLimitErrorr6  r<   )rý   c              3  ó&   K  — | ]	  }|€Œ|–— Œ y ­wrG   r1   )r¸   Úvs     r3   r»   z%classify_api_error.<locals>.<genexpr>Ì  s   è ø€ ÒP˜!À!Á-”AÑPùó   ‚Šc              3  ó.   •K  — | ]  } |‰«      –— Œ y ­wrG   r1   )r¸   Ústager  s     €r3   r»   z%classify_api_error.<locals>.<genexpr>Ì  s   øè ø€ Ò>¨U¡ a§Ñ>ùs   ƒr6   z (endpoint: ú))r8   r:   r;   r>   r1   )r@  rŽ  Ú_extract_status_coder   r-   Ú_extract_error_bodyrô   Ú_build_error_msgr=   Únextr‹  Ú
_V_UNKNOWNÚ_extract_messagerA  r   r   Ú_off_route_hostr5   )rö   r:   r;   rù   rú   rû   rü   rŒ  rŽ  r8   r÷   rÝ   r>   ÚhostÚbaser  s                  @r3   r!  r!  µ  s   ø€ õ :Ü& uÓ-€KàÐœt E›{×3Ñ3Ð7GÒGØˆÜ˜uÓ%€DÜØˆ{˜DÔ"2°5¸$Ó"?ÀÈ5Ø�~ |´S¸ºÀRÓ5HÙ& x°Ó9ô	€Aô
 ÑPÓ>´gÔ>ÔPÔR\Ó]€GÜ˜u dÓ+€GØˆxÑœRŸW™W¤b×&7Ñ&7Ð8Ñ8ô ˜qÓ!ˆÙØ ˜	 ¨d¨V°1Ð5ˆGØ&°HÀuÐY`Ña€DÜÑ1Ð0 Ð0¨Ð0Ñ1Ð1r2   c                ó†   — ddl m} ddlm}  || j                  «      }|r || j
                  | j                  «      du ry|S )zeThe contacted host when ``base_url`` is set and is not the provider's own endpoint; ``""`` otherwise.r   )Úprovider_owns_route)Úbase_url_hostnameTr<   )Úhermes_cli.route_identityr   Úutilsr¡  rü   r	  )r  r   r¡  r�  s       r3   rœ  rœ  Ù  s8   € å=Ý'Ù˜QŸZ™ZÓ(€DÙÑ& q§¡¸¿
¹
ÓCÀtÑKØØ€Kr2   Úupstream_unavailablec                ó  ‡ — ‰ j                   t        v rt        S ‰ j                  dk(  xr ‰ j                   t        k(  }|xs t        ˆ fd„dt        z   D «       «      }|rt        S t        ˆ fd„t        D «       «      rt        S t        S )Nz	xai-oauthc              3  ó:   •K  — | ]  }|‰j                   v –— Œ y ­wrG   r<  r=  s     €r3   r»   z_status_403.<locals>.<genexpr>ð  s   øè ø€ Òp¨a˜q A§E¡EœzÑpùr>  )ri   zspending limitc              3  ó:   •K  — | ]  }|‰j                   v –— Œ y ­wrG   r<  r=  s     €r3   r»   z_status_403.<locals>.<genexpr>ö  s   øè ø€ Ò
:˜!ˆ1�—‘Œ:Ñ
:ùr>  )r  Ú_403_TRANSIENT_CODESÚ_V_OVERLOADEDr	  Ú_XAI_SPENDING_LIMIT_ERROR_CODErÃ   Ú_BILLING_PATTERNSrÕ   Ú_UPSTREAM_BLOCKED_PATTERNSÚ_V_UPSTREAM_BLOCKEDrX  )r  Ú	xai_spendr   s   `  r3   Ú_status_403r¯  ë  su   ø€ Ø‡v�vÔ%Ñ%ÜÐà—‘ ;Ñ.Ò[°1·6±6Ô=[Ñ3[€IØÒpœ3ÓpÐ3[Ô^oÑ3oÔpÓp€GÙÜÐô Ó
:Ô9Ô
:Ô:Ü"Ð"ÜÐr2   c                óÆ   — | j                   t        v rt        S t        | j                  t
        «      }|�|S t        | j                  | j                  «      rt        S t        S rG   )r  Ú_BILLING_ERROR_CODESrÕ   rÞ   rÆ   Ú
_404_RULESÚ_model_id_missing_known_prefixr
  r	  Ú_V_MODEL_NOT_FOUNDrš  )r  rÝ   s     r3   Ú_status_404rµ  û  sS   € ð 	‡v�vÔ%Ñ%ÜÐÜ˜1Ÿ5™5¤*Ó-€GØÐØˆô "@ÀÇÁÈaÏoÉoÔ!^ÔÐnÔdnÐnr2   c                óú  ‡ — ‰ j                   t        v rt        S t        ˆ fd„t        D «       «      rt
        S t        ‰ j                  ‰ j                  «      r9t        ‰ j                  «      }|rd|ini }t        t        j                  d|¬«      S ‰ j                   dk(  xs" t        ˆ fd„dt        z   t        z   D «       «      }t        ˆ fd„t        D «       «      }|r3|s1t!        ‰ j"                  ‰ j                  ‰ j$                  «      st        S t'        ‰ j"                  ‰ j                  ‰ j$                  «      }|r9t        t        j(                  fi t*        ¤d	d
t-        j,                  «       |z   ii¤ŽS t.        S )Nc              3  ó:   •K  — | ]  }|‰j                   v –— Œ y ­wrG   r<  r=  s     €r3   r»   z_status_429.<locals>.<genexpr>  s   øè ø€ Ò
4˜!ˆ1�—‘Œ:Ñ
4ùr>  Úupstream_providerTr:  Úusage_limit_reachedc              3  ó:   •K  — | ]  }|‰j                   v –— Œ y ­wrG   r<  r=  s     €r3   r»   z_status_429.<locals>.<genexpr>  s   øè ø€ ò 8ØˆˆQ�U‰UŒ
ñ8ùr>  )r¹  c              3  ó:   •K  — | ]  }|‰j                   v –— Œ y ­wrG   r<  r=  s     €r3   r»   z_status_429.<locals>.<genexpr>  s   øè ø€ ÒG¨Q˜a 1§5¡5œjÑGùr>  r@   r9  )r  r±  rÕ   rÃ   Ú_OVERLOADED_PATTERNSr©  Ú_is_openrouter_upstream_errorr÷   r	  Ú_extract_upstream_provider_namer±   rA  r   rm  r«  Ú_RATE_LIMIT_PATTERNSÚ!_has_usage_limit_transient_signalrÆ   r  Ú_rate_limit_reset_secondsr   Ú_ROTATE_FALLBACKrB  Ú_V_RATE_LIMIT)r  ÚupstreamrÖ   Ú
quota_wallÚexplicit_rate_limitÚresets   `     r3   Ú_status_429rÈ  	  s<  ø€ ð 	‡v�vÔ%Ñ%ÜÐô Ó
4Ô3Ô
4Ô4ÜÐä$ Q§V¡V¨Q¯_©_Ô=Ü2°1·6±6Ó:ˆÙ19Ð" HÑ-¸rˆÜ”"×(Ñ(¸$ÈcÔRÐRð
 —‘Ð0Ñ0ò ´Có 8Ø4Ô7LÑLÔO`Ñ`ô8ó 5€Jô ÓGÔ2FÔGÓGÐÙÑ-Ô6WÐXY×X]ÑX]Ð_`×_eÑ_eÐgh×gpÑgpÔ6qÜÐä% a§e¡e¨Q¯V©V°Q·Y±YÓ?€EÙÜ”"—-‘-ÑeÔ#3ÑeÀJÔPT×PYÑPYÓP[Ð^cÑPcÐCdÒeÐeÜÐr2   c                óð   ‡ — t        ˆ fd„t        D «       «      xs ‰ j                  t        v }|r&t	        ‰ j
                  ‰ j                  «      st        S t        ‰ j
                  t        «      xs t        S )Nc              3  ó:   •K  — | ]  }|‰j                   v –— Œ y ­wrG   r<  r=  s     €r3   r»   z_status_5xx.<locals>.<genexpr>,  s   øè ø€ ÒF A�Q˜!Ÿ%™%”ZÑFùr>  )rÃ   Ú_REQUEST_VALIDATION_PATTERNSr  Ú_5XX_VALIDATION_CODESÚ#_is_server_injected_param_rejectionrÆ   r	  rf  rÞ   Ú_OVERFLOW_AS_5XX_RULESr‡  )r  Ú
validations   ` r3   Ú_status_5xxrÐ  )  sW   ø€ ô ÓFÔ)EÔFÓFÒiÈ!Ï&É&ÔTiÐJi€JÙÔ=¸a¿e¹eÀQÇ_Á_ÔUÜÐÜ˜Ÿ™Ô5Ó6ÒI¼/ÐIr2   c                ó”   ‡ — t        ˆ fd„t        D «       «      xr t        ˆ fd„t        D «       «      } |di |rt        ¤ŽS t        ¤ŽS )zYDisambiguate 402: "usage limit, try again in 5 minutes" is a periodic quota, not billing.c              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   rÑ   s     €r3   r»   z _classify_402.<locals>.<genexpr>4  s   øè ø€ ÒB q�A˜”NÑBùr¼   c              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   rÑ   s     €r3   r»   z _classify_402.<locals>.<genexpr>4  s   øè ø€ ò KØˆˆYŒñKùr¼   r1   )rÃ   rm  Ú_USAGE_LIMIT_TRANSIENT_SIGNALSrÃ  rÕ   )rÅ   Ú	result_fnÚ	transients   `  r3   rn  rn  2  sJ   ø€ äÓBÔ,AÔBÓBò Äsó KÜ >ôKó H€Iñ ÑD©œÑDÐD¼
ÑDÐDr2   c                ó4  — ddl m} t        | t        «      r| ndD ]{  }t        |t        «      r|j                  d«      nd}t        |t        «      r|j                  d«      n|}t        |t        «      sŒZ|j                  d«      sŒlt        |«      |kD  sŒ{ y y	)
zÊTrue when a rejected ``content`` list carries a ``data:image/`` part the shrink pass would rewrite
    (over ``conversation_compression._IMAGE_SHRINK_TARGET_BYTES``; below it a shrink retry is a no-op).r   )Ú_IMAGE_SHRINK_TARGET_BYTESr1   Ú	image_urlNÚurlzdata:image/TF)	Úagent.conversation_compressionrØ  r$  ÚlistrP   rM   r=   Ú
startswithÚlen)ÚcontentrØ  ÚpartÚimagerÚ  s        r3   Ú_has_large_inline_imagerâ  :  s}   € õ Jä% g¬tÔ4‘¸"ò ˆÜ)3°D¼$Ô)?�—‘˜Ô%ÀTˆÜ",¨U´DÔ"9ˆe�i‰i˜Ô¸uˆÜ�cœ3Õ C§N¡N°=Õ$AÄcÈ#ÃhÐQkÓFkÙð	ð
 r2   c                ó  — t        | t        «      r| j                  d«      nd}t        |t        «      r|ndD ]Ã  }t        |t        «      r|j                  d«      nd}|j                  d«      dk7  st        |t        «      rt	        |«      dk  rŒY|D �cg c]  }t        |«      j                  «       ‘Œ }}|dd dd	gk(  sŒŠ|d
d ddgk(  sŒ•t        d„ |D «       «      rŒ¨t        |j                  d«      «      sŒÃ y yc c}w )uÒ  400 rejecting a *message* ``content`` field whose rejected value carries a large inline image.

    Nebius Token Factory caps a single image at 10 MiB and reports the violation through the field that
    failed to coerce â€” pydantic ``{"type": "string_type", "loc": ["body","messages",N,"content","str"],
    "msg": "Input should be a valid string", "input": [...]}`` â€” naming no size vocabulary, so the
    keyword multimodal *tool*-content rule (#104731) claimed it and spent its retry stripping tool images
    that were never there (#112473). The same list-shaped content with a small image succeeds, so the
    image bytes are the trigger. Tool-scoped locs (``messages.N.tool.content.str``) stay with #104731.
    ÚdetailNr1   Úlocr   Ústring_typeé   r÷   r  éþÿÿÿrß  r=   c              3  ó>   K  — | ]  }|j                  d «      –— Œ y­w)ÚtoolN)rÝ  ©r¸   Úxs     r3   r»   z7_oversized_message_content_rejection.<locals>.<genexpr>W  s    è ø€ ò ^
Ø%&ˆA�L‰L˜× ñ^
ùs   ‚ÚinputTF)	r$  rP   rM   rÜ  rÞ  r=   r½   rÃ   râ  )r÷   Údetailsrä  rå  rì  Úpartss         r3   Ú$_oversized_message_content_rejectionrð  G  sñ   € ô %/¨t´TÔ$:ˆd�h‰h�xÔ À€GÜ'¨´Ô6‘'¸Bò ˆÜ#-¨f´dÔ#;ˆf�j‰j˜ÔÀˆØ�:‰:�fÓ Ò.´jÀÄdÔ6KÌsÐSVËxÐZ[Ê|ØØ),Ö- A”�Q“—‘•Ð-ˆÐ-Ø��!ˆ9˜ Ð,Ó,°°r°s°À	È5Ð?QÓ1QÔZ]ñ ^
Ø*/ô^
õ [
ä% f§j¡j°Ó&9Õ:Ùðð ùò .s   Â C?c                óÚ  ‡— | j                   | j                  cŠ}t        | j                  «      rt        S t        ‰t        «      }|�|S t        ‰v rt        S |dk(  s d‰v sd‰v rd‰v sd‰v sd‰v sd‰v rd‰v sd‰v rt        S t        ‰v st        ‰«      rt        S t        ‰| j                  «      rt        S t!        ˆfd	„t"        D «       «      rt$        S t!        ˆfd
„t&        D «       «      rt(        S t!        ˆfd„t*        D «       «      s|t,        v rt.        S t!        ˆfd„t0        D «       «      s|dk(  r2t2        j5                  d| j6                  | j8                  ‰«       t.        S |t:        v rt<        S t        ‰t>        «      }|�|S tA        d„ d„ tC        | j                  «      D «       D «       d«      }tE        |«      dk  xs |dv }|r| jG                  ddd«      rtH        S t.        S )uV   400 Bad Request â€” image/tool shapes, request-shape rejections, overflow, or generic.r%   zencrypted content for itemzcould not be verifiedz0could not decrypt the provided encrypted_contentz2encrypted content could not be decrypted or parsedÚencrypted_contentzwas not issued to this callerz1conflicting authenticated continuation identitiesc              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   rK  s     €r3   r»   z _classify_400.<locals>.<genexpr>…  s   øè ø€ Ò
;˜ˆ1�Œ8Ñ
;ùr¼   c              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   rK  s     €r3   r»   z _classify_400.<locals>.<genexpr>‡  s   øè ø€ Ò
8˜ˆ1�Œ8Ñ
8ùr¼   c              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   rK  s     €r3   r»   z _classify_400.<locals>.<genexpr>Š  s   øè ø€ Ò
6˜ˆ1�Œ8Ñ
6ùr¼   c              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   rK  s     €r3   r»   z _classify_400.<locals>.<genexpr>Ž  s   øè ø€ Ò
<˜ˆ1�Œ8Ñ
<ùr¼   ry   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  — | ]	  }|sŒ|–— Œ y ­wrG   r1   ©r¸   r¹   s     r3   r»   z _classify_400.<locals>.<genexpr>Ÿ  s   è ø€ Òn˜1Òlm”QÑnùr’  c              3  ór   K  — | ]/  }t        |xs d «      j                  «       j                  «       –— Œ1 y­w)r<   N©r=   r  r½   rë  s     r3   r»   z _classify_400.<locals>.<genexpr>Ÿ  s*   è ø€ Ò hÀ!¤ Q¢W¨"£×!3Ñ!3Ó!5×!;Ñ!;×!=Ñ hùs   ‚57r<   é   >   r<   rö   gš™™™™™Ù?i€8 éP   )%rÆ   r  rð  r÷   Ú_V_IMAGE_TOO_LARGErÞ   Ú_IMAGE_TOOL_RULESÚ&CODEX_ACCOUNT_MODEL_ENTITLEMENT_MARKERÚ_V_MODEL_ENTITLEMENTrU  Ú_REASONING_MANDATORY_PATTERNrÎ   Ú_V_REASONING_MANDATORYrÍ  r	  r‡  rÃ   Ú_MALFORMED_TOOL_ARGS_PATTERNSÚ_V_MALFORMED_TOOL_ARGSÚ_ROLE_ALTERNATION_PATTERNSÚ_V_ROLE_ALTERNATIONÚ_400_VALIDATION_PATTERNSÚ_400_VALIDATION_CODESrf  Ú_INVALID_MESSAGE_BODY_PATTERNSr  Úwarningrû   rù   Ú_MEMORY_CEILING_ERROR_CODESr©  Ú_400_TAIL_RULESr™  Ú_body_message_candidatesrÞ  r  r~  )r  r  rÝ   Úbody_msgÚ
is_genericrÆ   s        @r3   Ú_classify_400r  ^  så  ø€ à—‘�q—v‘v€I€Cˆô ,¨A¯F©FÔ3Ü!Ð!Ü˜3Ô 1Ó2€GØÐØˆô .°Ñ4Ü#Ð#ð Ð*Ò*Ð.IÈSÑ.PØ$¨Ñ+Ð0GÈ3Ñ0NØ	;¸sÑ	Bà<ÀÑCð 	˜sÑ"Ð'FÈ#Ñ'Mð 	<¸sÑBä#Ð#ô
 $ sÑ*Ô.JÈ3Ô.OÜ%Ð%ô +¨3°·±Ô@ÜÐÜ
Ó
;Ô:Ô
;Ô;Ü%Ð%Ü
Ó
8Ô7Ô
8Ô8Ü"Ð"ä
Ó
6Ô5Ô
6Ô6¸$ÔBWÑ:WÜÐô Ó
<Ô;Ô
<Ô<ÀÐH^Ò@^Ü�‰ðð ŸN™N¨A¯O©O¸Sô		
ô Ðð Ô*Ñ*ÜÐÜ˜3¤Ó0€GØÐØˆô ÑnÑ hÔG_Ð`a×`fÑ`fÓGgÔ hÔnÐprÓs€HÜ�X“ Ñ#Ò@ x°=Ð'@€JÙ�a—o‘o c¨5°"Ô5Ü"Ð"ÜÐr2   c                ó|   — t        | j                  «      rt        S t        | j                  t
        «      xs t        S )zT422: pydantic relays report the same content-field shapes as 400 (#104731, #112473).)rð  r÷   rý  rÞ   rÆ   rþ  rf  ©r  s    r3   Ú_classify_image_tool_422r  ¦  s+   € ä+¨A¯F©FÔ3Ü!Ð!Ü˜Ÿ™Ô0Ó1ÒD´_ÐDr2   c                ó   — t         S rG   )Ú_V_AUTH_ROTATEr  s    r3   ú<lambda>r  ²  s   € ¤~€ r2   c                ó6   — t        | j                  t        «      S rG   )rn  rÆ   rP   r  s    r3   r  r  ²  s   € ÄmÐTU×TYÑTYÔ[_ÓF`€ r2   c                ó   — t         S rG   )r{  r  s    r3   r  r  ³  s   € ´z€ r2   c                ó   — t         S rG   )Ú_V_PAYLOAD_TOO_LARGEr  s    r3   r  r  ³  s   € ÔRf€ r2   c                ó   — t        | «      S rG   )r  r  s    r3   r  r  ´  s   € Ô+¨AÓ.€ r2   c                óF   — t        | j                  t        «      xs t        S rG   ©rÞ   rÆ   rÎ  r©  r  s    r3   r  r  ¶  ó   € ”< §¡Ô'=Ó>ÒOÄ-€ r2   c                óF   — t        | j                  t        «      xs t        S rG   r  r  s    r3   r  r  ·  r  r2   )r3  i‘  i’  r?  i”  i˜  i�  i¦  r6  r…  iö  i÷  i  z$Dict[int, Callable[[_Ctx], Verdict]]rˆ  )Úresets_in_secondsÚ	resets_atr9  r8  )zretry-afterzRetry-Afterzx-ratelimit-resetzX-RateLimit-Resetc                ó  ‡ ‡— t        ˆ fd„t        D «       «      ry|t        |«      fD �cg c]  }t        |t        «      sŒ|‘Œ }}t        d„ |D «       «      ry‰r$t        ‰d«      rt        ˆfd„t        D «       «      S yc c}w )z\Whether a usage-limit response identifies a reset window (message, body fields, or headers).c              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   )r¸   ÚpatternrÅ   s     €r3   r»   z4_has_usage_limit_transient_signal.<locals>.<genexpr>Ã  s   øè ø€ Ò
N Gˆ7�iÔÑ
Nùr¼   Tc              3  óX   K  — | ]"  }t         D ]  }|j                  |«      d v–— Œ Œ$ y­w©rÿ   N)Ú_RESET_FIELDSrM   )r¸   ÚpayloadÚfs      r3   r»   z4_has_usage_limit_transient_signal.<locals>.<genexpr>Æ  s*   è ø€ Ò
[°Ì]Ò
[Èˆ7�;‰;�q‹> Ô+Ð
[Ð+Ñ
[ùs   ‚(*rM   c              3  óD   •K  — | ]  }‰j                  |«      d v–— Œ y­wr&  ©rM   )r¸   ÚhÚresponse_headerss     €r3   r»   z4_has_usage_limit_transient_signal.<locals>.<genexpr>É  s"   øè ø€ ÒUÀÐ#×'Ñ'¨Ó*°*Ô<ÑUùs   ƒ F)rÃ   rÔ  Ú
_error_objr$  rP   ÚhasattrÚ_RESET_HEADERS)rÅ   r÷   r-  rÒ   Úpayloadss   ` `  r3   rÀ  rÀ  Á  ss   ù€ ä
Ó
NÔ/MÔ
NÔNØØ ¤*¨TÓ"2Ð3ÖK�a´zÀ!ÄTÕ7J’ÐK€HÐKÜ
Ñ
[¸8Ô
[Ô[ØÙœGÐ$4°eÔ<ÜÓUÄnÔUÓUÐUØùò Ls   «BÁBc                óx  — ddl m}m} d„ |t        |«      fD «       D ]ˆ  }t        D ]}  }|j                  |«      }|dv rŒ|j                  d«      rDt        |t        t        f«      r.t        dt        |«      t        j                  «       z
  «      c c S  ||«      x}€Œy|c c S  ŒŠ  ||«      x}�|S  || «      S )z»Seconds until a 429's window reopens, from the body's reset fields, ``Retry-After`` or the
    message grammar (``retry after Ns`` / ``resets in 4hr``); None when the response names none.r   )Úparse_retry_after_secondsÚreset_delay_from_messagec              3  óB   K  — | ]  }t        |t        «      sŒ|–— Œ y ­wrG   )r$  rP   rò   s     r3   r»   z,_rate_limit_reset_seconds.<locals>.<genexpr>Ñ  s   è ø€ ÒO˜!¼:ÀaÌÕ;N”AÑOùs   ‚˜rÿ   Ú_atg        )Úagent.retry_utilsr3  r4  r.  r'  rM   Úendswithr$  rø   r  rÀ   rB  )	rÅ   r÷   r-  r3  r4  r(  Únamer  Úsecondss	            r3   rÁ  rÁ  Í  s»   € ÷ VÙO ¤j°Ó&6Ð7ÔOò ˆÜ!ò 	ˆDØ—K‘K Ó%ˆEØ˜
Ñ"ØØ�}‰}˜UÔ#¬
°5¼3Ä¸,Ô(GÜ˜3¤ e£¬t¯y©y«{Ñ :Ó;Ô;Ù4°UÓ;Ð;�ÑHØ”ñ	ðñ -Ð-=Ó>Ð>ˆÐKØˆÙ# IÓ.Ð.r2   c                ó¬   — | xs dj                  «       }|rd|v ry	 ddlm} t         ||xs dj                  «       |«      «      S # t        $ r Y yw xY w)zçTrue when a bare model id is only known to the provider as ``vendor/id``.

    Never guesses: an id absent from the curated catalogue returns False so real
    endpoint problems keep their retryable ``unknown`` classification.
    r<   ú/Fr   )Úsuggest_prefixed_model_id)r  Úhermes_cli.model_normalizer=  rA   rõ   )r;   r:   r9  r=  s       r3   r³  r³  ß  s\   € ð ŠK�R×ÑÓ €DÙ�3˜$‘;ØðÝHÜÑ-¨xª~¸2×.DÑ.DÓ.FÈÓMÓNÐNøÜò Ùðús   �)A Á	AÁAc                óò   ‡ ‡— |xs dj                  «       j                  «       Št        j                  «       D ]<  \  }}‰ sŒ	|‰ v sŒt	        ˆ fd„t
        D «       «      sŒ't	        ˆfd„|D «       «       c S  y)zñTrue when a 400 blames a one-route-only parameter this route never sends.

    Conservative: known parameters only, and only when ``provider`` is not a
    sender, so a genuine bad parameter (``max_tokens`` on GPT-5) stays format_error.
    r<   c              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   )r¸   ÚwrÅ   s     €r3   r»   z6_is_server_injected_param_rejection.<locals>.<genexpr>÷  s   øè ø€ Ò3cÀq°A¸´NÑ3cùr¼   c              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wrG   r1   )r¸   Úsenderr	  s     €r3   r»   z6_is_server_injected_param_rejection.<locals>.<genexpr>ø  s   øè ø€ ÒI°v˜6 ]Ô2ÑIùr¼   F)r  r½   r†   ÚitemsrÃ   Ú_PARAM_REJECTION_WORDS)rÅ   r:   ÚparamÚsendersr	  s   `   @r3   rÍ  rÍ  ï  so   ù€ ð ’^ ×*Ñ*Ó,×2Ñ2Ó4€MÜ8×>Ñ>Ó@ò J‰ˆˆwÚ˜ )Ò+´Ó3cÔLbÔ3cÕ0cÜÓIÀÔIÓIÐIÒIðJð r2   zrequest blocked.zunsupported content typec                ó  — | j                   dk7  s| j                  dvryt        | j                  t        «      r| j                  ni }t        |j                  d«      xs d«      j                  «       j                  «       t        k(  s"|s!t        | j                  v rd| j                  v ryt        d„ t        |«      D «       d«      }| j                  dk(  xr	 |t        k(  xs$ | j                  j                  «       d	t        › �k(  S )
u±  HTTP 400 / status-less ``{code: invalid_prompt, message: "Request blocked."}`` from
    ``openai-codex`` â€” as an SDK error body, a Responses ``error`` SSE frame, or the
    ``response.failed`` text ``"invalid_prompt: Request blocked."`` â€” or the bare
    ``{"detail": "Unsupported content type"}`` envelope the same backend returns for a rejected
    encrypted-reasoning replay (#51512). Both are exact envelopes, provider-gated.rç   )Nr3  Frä  r<   Tc              3  óp   K  — | ].  }|sŒt        |«      j                  «       j                  «       –— Œ0 y ­wrG   rú  rø  s     r3   r»   z4_is_codex_masked_replay_rejection.<locals>.<genexpr>  s&   è ø€ ÒY°ÒWX”S˜“V—\‘\“^×)Ñ)×+ÑYùs   ‚6Š,6Úinvalid_promptzinvalid_prompt: )r	  r8   r$  r÷   rP   r=   rM   r  r½   Ú!_CODEX_UNSUPPORTED_CONTENT_DETAILrÆ   r™  r  r  Ú_CODEX_MASKED_REPLAY_MESSAGE)r  r÷   r  s      r3   rS  rS     sÛ   € ð 	‡�˜.Ò(¨A¯M©MÀÑ,LØÜ §¡¬Ô-ˆ1�6Š6°2€DÜ
ˆ4�8‰8�HÓÒ# Ó$×*Ñ*Ó,×2Ñ2Ó4Ô8YÒYÙÔ6¸!¿%¹%Ñ?ÀHÐPQ×PUÑPUÑDUàäÑYÔ5MÈdÓ5SÔYÐ[]Ó^€HØ�F‰FÐ&Ñ&ÒS¨8Ô7SÑ+Sò Ø	�‰�‰‹Ð+Ô,HÐ+IÐJÑJðr2   c                óp   — t        | t        «      r| j                  d«      nd}t        |t        «      r|S i S )z1``body["error"]`` when it is a dict, else ``{}``.rö   N)r$  rP   rM   )r÷   Úerrs     r3   r.  r.    s/   € ä)¨$´Ô5ˆ$�(‰(�7Ô
¸4€CÜ˜S¤$Ô'ˆ3Ð/¨RÐ/r2   c                óÖ   — t        | t        «      r| j                  «       sy	 t        j                  | «      }t        |t        «      r|S dS # t        j
                  t        f$ r Y yw xY w)zVParse a JSON object string; None for non-strings, blanks, invalid JSON or non-objects.N)r$  r=   r  ÚjsonÚloadsÚJSONDecodeErrorÚ	TypeErrorrP   )ÚtextÚinners     r3   Ú
_json_dictrV    s_   € ä�tœSÔ! d§j¡j¤lØðÜ—
‘
˜4Ó ˆô ˜u¤dÔ+ˆ5Ð5°Ð5øô × Ñ ¤)Ð,ò Ùðús   £A ÁA(Á'A(c                óð   — | j                  di «      }t        |t        «      rt        |j                  d«      «      nd}|r5t	        t        |«      j                  d«      xs d«      j                  «       S dS )zOLowercased inner message from OpenRouter's ``error.metadata.raw`` JSON wrapper.ÚmetadataÚrawNr>   r<   )rM   r$  rP   rV  r=   r.  r½   )Úerr_objrX  rU  s      r3   Ú_openrouter_wrapped_messager[  %  s`   € à�{‰{˜: rÓ*€HÜ/9¸(ÄDÔ/IŒJ�x—|‘| EÓ*Ô+Èt€EÙBGŒ3Œz˜%Ó ×$Ñ$ YÓ/Ò5°2Ó6×<Ñ<Ó>ÐOÈRÐOr2   c                óÐ  — t        | «      j                  «       }dx}}t        |t        «      rtt	        |«      }t        |j                  d«      xs d«      j                  «       xs, t        |j                  d«      xs d«      j                  «       }|rt        |«      nd}|g}|r||vr|j                  |«       |r||vr||vr|j                  |«       dj                  |«      S )z—Lowercased str(error) + body message + OpenRouter-wrapped upstream message
    (OpenAI SDK's APIStatusError.__str__ omits the body, so it is appended).r<   r>   ú )	r=   r½   r$  rP   r.  rM   r[  ÚappendÚjoin)rö   r÷   Úraw_msgr  Úmetadata_msgrZ  rï  s          r3   r˜  r˜  ,  sÎ   € ô �%‹j×ÑÓ €GØ Ð €Hˆ|Ü�$œÔÜ˜TÓ"ˆÜ�w—{‘{ 9Ó-Ò3°Ó4×:Ñ:Ó<ÒfÄÀDÇHÁHÈYÓDWÒD]Ð[]Ó@^×@dÑ@dÓ@fˆÙ?FÔ2°7Ô;ÈBˆØˆI€EÙ�H GÑ+Ø�‰�XÔÙ˜¨GÑ3¸ÈHÑ8TØ�‰�\Ô"Ø�8‰8�E‹?Ðr2   c              #  ó˜  K  — t        | «      j                  d«      –— | j                  d«      –— | j                  d«      –— | j                  d«      }t        |t        «      r|j                  d«      nd–— | j                  d«      }t        |t        «      r|j                  d«      –— yt        |t        «      r|–— yd–— y­w)z\Body message fields in priority order (OpenAI, flat, litellm/Bedrock proxy, FastAPI shapes).r>   ÚerrorMessageÚ	errorArgsr6   Nrä  )r.  rM   r$  rP   r=   )r÷   Úargsrä  s      r3   r  r  =  s    è ø€ ä
�TÓ
×
Ñ
˜yÓ
)Ò)Ø
�(‰(�9Ó
ÒØ
�(‰(�>Ó
"Ò"Ø�8‰8�KÓ €DÜ *¨4´Ô 6ˆ$�(‰(�8Ô
¸DÒ@ð
 �X‰X�hÓ€FÜ#-¨f´dÔ#;ˆ&�*‰*�YÓ
ÓlÌ:ÐV\Ô^aÔKbÀÓlÐhlÓlùs   ‚CC
c                ó”   — | }t        d«      D ]7  } ||«      }|�|c S t        |dd«      xs t        |dd«      }|�||u r |S |}Œ9 |S )z]First non-None ``pick(exc)`` over the error and its __cause__/__context__ chain (max 5 deep).é   NÚ	__cause__Ú__context__)Úranger#  )rö   Úpickr‰  ÚcurrentÚ_ÚfoundÚcauses          r3   r  r  L  sm   € à€GÜ�1‹Xò ˆÙ�W“ˆØÐØŠLÜ˜ ¨dÓ3Ò\´w¸wÈÐW[Ó7\ˆØˆ=˜E WÑ,Øà€Nð ‰ðð €Nr2   c                óš   — t        | dd «      }t        |t        «      r|S t        | dd «      }t        |t        «      rd|cxk  rdk  r|S  d S )Nr8   rD  éd   r†  )r#  r$  rø   )r  r  s     r3   Ú
_status_ofrr  Z  sP   € Ü�3˜ tÓ,€DÜ�$œÔØˆÜ�3˜ $Ó'€DÜ˜d¤CÔ(¨S°DÔ->¸3Ò->ˆ4ÐHÐ->ÀDÐHr2   c                óÊ   — t        | dd «      }t        |t        «      r|S t        | dd «      }	 |�|j                  «       nd }t        |t        «      r|S d S # t        $ r Y y w xY w)Nr÷   Úresponse)r#  r$  rP   rP  rõ   )r  r÷   rt  Ú	json_bodys       r3   Ú_body_ofrv  b  sn   € Ü�3˜ Ó%€DÜ�$œÔØˆÜ�s˜J¨Ó-€HðØ'/Ð';�H—M‘M”OÀˆ	ô # 9¬dÔ3ˆ9Ð=¸Ð=øô ò Ùðús   ®A Á	A"Á!A"c                óV   — t        t        | dd «      dd «      }|rt        |d«      r|S d S )Nrt  r  rM   )r#  r/  )r  r  s     r3   r  r  n  s/   € Ü”g˜c :¨tÓ4°iÀÓF€GÙ¤'¨'°5Ô"9ˆ7ÐC¸tÐCr2   c                ó$   — t        | t        d«      S )z3HTTP status code from the error or its cause chain.N)r  rr  ©rö   s    r3   r–  r–  s  s   € ä˜U¤J°Ó5Ð5r2   c                ó$   — t        | t        i «      S )z?Structured error body from an SDK exception or its cause chain.)r  rv  ry  s    r3   r—  r—  x  s   € ä˜U¤H¨bÓ1Ð1r2   c                óä  ‡ — t        ‰ t        «      sy‰ j                  di «      }t        |t        «      rì|j                  d«      xs |j                  d«      xs d}t        |t        «      s|j                  d«      xs |}t        |t        «      r3|j	                  «       r#|j	                  «       dk7  r|j	                  «       S |j                  d«      }|rIt        |t        «      r9|j	                  «       j                  d«      rt        t        |«      d	d
«      }|r|S t        ˆ fd„|D «       d«      }t        |t        t        f«      rt        |«      j	                  «       nd}|r|dk7  r|S dS )aq  Code/type from ``payload.error`` or a top-level key; ``"400"`` is not a code.
    ``peek_message`` also parses a JSON ``error.message`` for a nested code
    (Responses API surfaces ``invalid_encrypted_content`` this way). Gemini
    puts the HTTP status in ``error.code`` and the symbolic code
    (``UNAVAILABLE``) in ``error.status``, so a numeric code defers to it.r<   rö   r  r   rD  Ú400r>   ú{)r  r  Fc              3  ód   •K  — | ]'  }‰j                  |«      sŒ‰j                  |«      –— Œ) y ­wrG   r+  )r¸   r*  r(  s     €r3   r»   z%_code_from_payload.<locals>.<genexpr>‘  s#   øè ø€ ÒD A°W·[±[Àµ^�—‘˜Q—ÑDùs   ƒ0š0)
r$  rP   rM   r=   r  rÝ  Ú_code_from_payloadrV  r™  rø   )r(  Útop_keysÚpeek_messageÚ	error_objr  r>   Únested_coderT  s   `       r3   r  r  }  s%  ø€ ô �gœtÔ$ØØ—‘˜G RÓ(€IÜ�)œTÔ"Ø�}‰}˜VÓ$ÒC¨	¯©°fÓ(=ÒCÀˆÜ˜$¤Ô$Ø—=‘= Ó*Ò2¨dˆDÜ�dœCÔ  T§Z¡Z¤\°d·j±j³lÀeÒ6KØ—:‘:“<ÐØ—-‘- 	Ó*ˆÙœJ w´Ô4¸¿¹»×9SÑ9SÐTWÔ9XÜ,¬Z¸Ó-@ÐBXÐZ_Ó`ˆKÙØ"Ð"ÜÓD¨ÔDÀbÓI€DÜ *¨4´#´s°Ô <Œ3ˆt‹9�?‰?ÔÀ"€DÙ˜D EšMˆ4Ð1¨rÐ1r2   c                ó$   — | rt        | dd«      S dS )z4Extract an error code string from the response body.)r  r  Ú	errorCodeTr<   )r  )r÷   s    r3   r  r  –  s   € áRVÔ˜dÐ$GÈÓNÐ^Ð\^Ð^r2   c                óˆ   — t        d„ t        |xs i «      D «       d«      }|r|j                  «       dd S t        | «      dd S )zCExtract the most informative error message (structured body first).c              3  ód   K  — | ](  }t        |t        «      sŒ|j                  «       sŒ%|–— Œ* y ­wrG   )r$  r=   r  rø  s     r3   r»   z#_extract_message.<locals>.<genexpr>�  s&   è ø€ Òd�aÄ:ÈaÔQTÕCUÐZ[×ZaÑZaÕZc”Ñdùs   ‚0˜0©0Nr…  )r™  r  r  r=   )rö   r÷   rÆ   s      r3   r›  r›  ›  sD   € ä
ÑdÔ3°D²J¸BÓ?ÔdÐfjÓ
k€CÙˆC�I‰I‹K°°Ð5Ð5¤C¨£J°°Ð5Ð5r2   c                ó:  — t        | «      }t        |j                  d«      xs d«      j                  «       j	                  «       dk7  ry|xs dj                  «       j	                  «       dk(  ry|j                  d«      }t        |t        «      xr
 d|v xs d	|v S )
zŠOpenRouter's "Provider returned error" wrapper: the key is healthy, the
    upstream failed, so credential rotation is the wrong recovery.r>   r<   zprovider returned errorFÚ
openrouterTrX  rY  Úprovider_name)r.  r=   rM   r  r½   r$  rP   )r÷   r:   rN  rX  s       r3   r½  r½  ¡  s�   € ô �TÓ
€CÜ
ˆ3�7‰7�9ÓÒ# Ó$×*Ñ*Ó,×2Ñ2Ó4Ð8QÒQØØŠ�B×ÑÓ×%Ñ%Ó'¨<Ò7Øà�w‰w�zÓ"€HÜ�h¤Ó%Ò\¨5°HÐ+<Ò+[ÀÐS[Ð@[Ð\r2   c                óà   — t        | «      j                  d«      }t        |t        «      r|j                  d«      nd}t        |t        «      r |j                  «       r|j                  «       S dS )zCPull the upstream provider name out of OpenRouter's error metadata.rX  rŠ  N)r.  rM   r$  rP   r=   r  )r÷   rX  r9  s      r3   r¾  r¾  ®  sR   € ä˜$Ó×#Ñ# JÓ/€HÜ,6°xÄÔ,Fˆ8�<‰<˜Ô(ÈD€DÜ% d¬CÔ0°T·Z±Z´\ˆ4�:‰:‹<ÐKÀtÐKr2   )r6   r   r°   r   rN   ÚVerdict)rÅ   r=   rN   rA   )rÅ   r=   rN   rŒ  )rÅ   r=   rÛ   z#Sequence[tuple[Sequence[str], Any]]rN   úOptional[Verdict])r  rô   rN   r�  )rö   rõ   r:   r=   r;   r=   rù   rø   rú   rø   rû   rø   rü   r=   rŒ  r   rN   r5   )r  rô   rN   r=   )r  rô   rN   rŒ  )rÅ   r=   rÕ  zCallable[..., Any]rN   r   )rß  r   rN   rA   )r÷   r   rN   rA   )rÅ   r=   r÷   rP   rN   rA   )rÅ   r=   r÷   rP   rN   zOptional[float])r;   r=   r:   r=   rN   rA   )rÅ   r=   r:   r=   rN   rA   )r  z'_Ctx'rN   rA   )r÷   r   rN   rP   )rT  r   rN   úOptional[dict])rZ  rP   rN   r=   )rö   rõ   r÷   r   rN   r=   )r÷   rP   rN   zIterator[Any])rö   rõ   rk  zCallable[[Any], Any]r‰  r   rN   r   )r  r   rN   r7   )r  r   rN   rŽ  )r  r   rN   r   )rö   rõ   rN   r7   )rö   rõ   rN   rP   )r(  r   r€  zSequence[str]r�  rA   rN   r=   )r÷   rP   rN   r=   )rö   rõ   r÷   rP   rN   r=   )r÷   r   r:   r=   rN   rA   )r÷   r   rN   r9   )Çr0   Ú
__future__r   ÚenumrP  ÚloggingÚrerB  Údataclassesr   r   Útypingr   r   r   r	   r
   r   Ú	getLoggerr-   r  re  Ú&PROVIDER_STREAM_EMPTY_FRAME_ERROR_CODEÚEnumr   r5   r-  r«  rÔ   rª  Ú	frozensetr±  r¿  r¼  rm  rÔ  Ú_PAYLOAD_TOO_LARGE_PATTERNSÚ_IMAGE_TOO_LARGE_PATTERNSÚ_IMAGE_CORRUPT_PATTERNSÚ!_MULTIMODAL_TOOL_CONTENT_PATTERNSÚ_MEMORY_CEILING_PATTERNSr  Ú_CONTEXT_OVERFLOW_PATTERNSrÿ  Ú_MODEL_NOT_FOUND_PATTERNSrW  r	  r  r  rË  r†   rO   rE  rV  ra  Ú!_PROVIDER_POLICY_BLOCKED_PATTERNSrQ  Ú_AUTH_PATTERNSÚ!_EMPTY_PROVIDER_RESPONSE_PATTERNSÚ_TIMEOUT_MESSAGE_PATTERNSÚ_CONNECTION_MESSAGE_PATTERNSr  r|  rx  rz  r¬  r=   rŒ  r±   rÂ  rT  rA  r   rÕ   r   rÃ  r   r  rX  r   r´  r   r­  r    rR  r!   r   r#   rf  r   Ú_V_POLICY_BLOCKEDr   ry  r   r~  r   r  Úmapr   r   r   r,   r©  r‡  r{  rš  r   r   rý  Ú_V_IMAGE_CORRUPTr&   r%   Ú_V_MULTIMODALrU  r'   r  r$   r  r  r  rÍ   Úcompiler¾   rÌ   rÄ   rÈ   rÎ   r×   rÞ   rþ  rÎ  r²  r  rl  ro  rP   Úfromkeysrä   rg  rð   r  rÌ  Útupler  rô   r  r+  r&  r   r)   r(   r'  rC  rH  r[  rc  ri  rr  rƒ  rŠ  r‹  r!  rœ  r¨  r¯  rµ  rÈ  rÐ  rn  râ  rð  r  r  rˆ  r'  r0  rÀ  rÁ  r³  rÍ  rL  rK  rS  r.  rV  r[  r˜  r  r  rr  rv  r  r–  r—  r  r  r›  r½  r¾  r1   r2   r3   ú<module>r¬     s{	  ðòõ #ã Û Û Û 	Û ß (ß D× Dà	ˆ×	Ñ	˜8Ó	$€ð 'FÐ #ð *GÐ &ô
 �T—Y‘Yô  ðF ÷Bð Bó ðBð@ eÐ àÐ0Ð2HÐJZØÐ6Ð8TØ Ð"5Ð7LÐN`ØÐ7Ð9QÐSjØ˜.Ð*<Ð>Pð ðð !ðð ñÐ ð(  7Ð ð "HÐ ñ !ØÐ.Ð0BÐDZØÐ+Ð-OØÐ!;Ð=[ð Ð CØ'Ð)Gà)ð"ó Ð ðÐ ðÐ ð YÐ ð"Ð ðÐ ð*Ð ðÐ ð%Ð !ð(Ð ñ (ò )ó Ð ðÐ ð$ *jÐ &ðÐ ð .Ð ð "Ð#AÐCYØ+Ð-HØ0Ð2Gð"Ð ðÐ ð!Ð ð Ð ð ÐWð4Ð Ð 0ó ð UÐ ð [Ð ðÐ ð%Ð !ð$Ð  ð€ð%Ð !ðÐ ð Ð ñ #ò $ó Ð ðÐ ðÐ ðÐ ðÐ ð ˆs�Cˆx‰.€ó'ð 15ÈÑNÐ Ø %¸$Ñ?€Ø€á�—
‘
Ñ@ eÐ@Ð/?Ñ@€
Ù�2—=‘=Ñ5Ð$4Ñ5€Ù�B—G‘GÑA uÐAÐ0@ÑA€Ù�b—g‘gÑ1 Ñ1Ð Ù˜×*Ñ*Ñ>¨oÑ>Ð Ù˜×,Ñ,Ñ@°Ñ@Ð Ù˜×1Ñ1ÑE°_ÑEÐ á˜"×.Ñ.ÑT¸%ÐTÐCSÑTÐ Ù�R—_‘_Ñ8¨Ñ8€á�r×1Ñ1ÑE°_ÑEÐ Ù�×)Ñ)Ñ=¨_Ñ=€Ù˜×,Ñ,¸dÔCÐ Ù˜"×.Ñ.ÀÔEÐ Ù9<¸RÀ"Ç-Á-ÐQS×Q`ÑQ`Ðbd×blÑblÐnp×nxÑnxÐAyÓ9zÑ 6€ˆ 
¨JÙ')¨"×*<Ñ*<Ó'=¹rÀ"×BRÑBRÓ?SÐ $Ð Ð$Ù&(¨×)OÑ)OÓ&PÑRTÐUW×UqÑUqÓRrÐ #€Ð#Ù˜B×2Ñ2ÀEÐ[`ÔaÐ ñ ˜×,Ñ,Ñ@°Ñ@Ð ñ ˜BŸO™O°uÈeÔTÐ à7Ð ðÐ ð $˜Ÿ™ðLóÐ ð (˜RŸZ™Zð%óÐ ðÐ ó?óUó00óð '¨Ð6Ð9PÐRbÐ8cØÐ 2Ð3ðÐ ð '¨Ð8Ð;SÐUbÐ:cØÐ!4Ð5ðÐ ð ˜
Ð#Ð&GÐIZÐ%[ØÐ 2Ð3ð€
ð )Ø&Ð(9Ð:Ð=VÐXjÐ<kØ˜=Ð)Ð,=¸~Ð+Nð,ñ €ð 1°-Ð@Ø3Ð5IÐJØ2Ð4GÐHðJàL]ñ^Ð ð ˜=Ð)Ð,=¸~Ð+NØ˜=Ð)Ð,MÈÐ+_ØÐ!4Ð5¸ÈÐ7WØ&Ð(9Ð:Ð=VÐXjÐ<kØ 
Ð+Ð.JÈJÐ-WðÐ ð,Ø
‡m‚mÐNÙ�r—}‘}¸tÔDóFð,ð ‡m‚mÐ(¨*Ó5ð,ð ‡m‚mÐOÐQcÓdð	,ð
 ‡m‚mÐFÐH[Ó\ð,ð ‡m‚mÐ/°Ó?ð,ð  Ð!5ñ,Ð Ð(ó ð ,4¸xÐZbØ/7À8Ð^fñhÐ ð ˜Ð/Ø+À*ÐZiÑjØ.ÀMÑRñ:Ð Ð6ó ð -Ð.EÐFÐ Ø-Ð1HÐ0IÑIÐ Ù Ñ iÐ,HÔ iÓiÐ ð
 ÷
ð 
ó ð
ó<ó((ðV ^€ñ %Ø×Ñ˜~×AÒAÀ>×C\ÑC\Ø×#Ñ# ^×%EÑ%EÀ~×GgÒGgØ×%Ò%ð&ó Ð ð ?Áñ GJØ ôGJó BJñ JÐ ó(YóV0ófló
ócó-óDRð Ð%Ð'>À
ÐL^Ø�K ð:€Ð	6ó ð *,¸"Ø°&ÈaØØñ	!2Øð!2Ø#&ð!2Ø47ð!2àð!2à,/ð!2àHKð!2ð ð!2ð ð	!2ð
 ó!2óHñ !Ð"8Ð!9Ó:Ð óó oóó@JóEó
óó.EóPEð 
Ñ5Ñ<`Ø	˜;Ñ-AÑHfÙ	.Ø	˜;¨[Ù	OÙ	Oñ:Ð Ð6ó ð N€ØY€ó	ó/ó$ó 
ð  2Ð Ø$>Ð !óó(0ó6óPóó"móóIó	>óDó
6ó
2ó
2ó2_ó
6ó
]ôLr2   