+
    iHàj›.  ã                   ó‚   € R t ^ RIt^ RIt^ RIHtHtHt ^ RIHt Rt	R R lt
RtRtRtR R ltR	 R
 lt ! R R4      tR# )a  Provider API error summarising for ``AIAgent``.

Entitlement-failure detection, xAI subscription decoration, structured-detail coercion, and log-safe
redaction of provider error payloads.
Extracted from ``run_agent.py``; every method resolves through ``AIAgent``'s MRO unchanged.
N)ÚAnyÚDictÚOptional)Úredact_sensitive_textc                ó0   € V ^8„  d   QhR\         R\        /# ©é   ÚerrorÚreturn)ÚBaseExceptionÚbool)Úformats   "Ú</home/ubuntu/.hermes/hermes-agent/agent/api_error_summary.pyÚ__annotate__r   $   s   € ÷ _ñ _¬-ð _¼Dñ _ó    c                ó  a € \        S \        4      ;'       dp    \        S \        \        P                  34      '       * ;'       dC    \
        ;QJ d#    V 3R l\         4       F  '       g   K   R# 	  R# ! V 3R l\         4       4      # )zXTrue for a provider stream-parse ``ValueError`` (see ``PROVIDER_STREAM_PARSE_MARKERS``).c              3   óZ   <"  € T F   q\        S4      P                  4       9   x € K"  	  R # 5i©N©ÚstrÚlower)Ú.0Úmarkerr	   s   & €r   Ú	<genexpr>Ú1is_provider_stream_parse_error.<locals>.<genexpr>'   s#   øé € Ð]Ñ?\°Vœc %›j×.Ñ.Ó0Ö0Ó?\ùó   ƒ(+TF)Ú
isinstanceÚ
ValueErrorÚUnicodeEncodeErrorÚjsonÚJSONDecodeErrorÚanyÚPROVIDER_STREAM_PARSE_MARKERS)r	   s   fr   Úis_provider_stream_parse_errorr#   $   st   ø€ ä�uœjÓ)÷ ^ð ^´*¸UÔEWÔY]×YmÑYmÐDnÓ2oÔ.o÷ ^ð ^ß“Ô]Õ?\Ó]—”ð_Úð_ØÔ]Õ?\Ó]Ó]ð_r   uZ   â€” xAI rejected this OAuth account. NOTE: X Premium+ does NOT include xAI API access â€” only standalone SuperGrok subscribers can use this provider. Other possible causes: no Grok subscription, your tier doesn't include this model, or your quota is exhausted. Check https://grok.com/?_s=usage to see which, or run `/model` to switch providers.c                ó0   € V ^8„  d   QhR\         R\        /# )r   r   r
   )r   r   )r   s   "r   r   r   >   s   € ÷ ñ ¤Cð ¬Dñ r   c                ót   € RV 9   ;'       g-    RV 9   ;'       d    RV 9   ;'       g    RV 9   ;'       d    RV 9   # )zYxAI's permission-denied body text for an unsubscribed / under-tiered / exhausted account.z'do not have an active grok subscriptionzout of available resourcesÚgrokzdoes not have permission© )r   s   &r   Ú_is_xai_entitlement_textr(   >   sQ   € ð 	2°UÑ:÷ 	Eð 	EØ(¨EÑ1×EÐE°fÀ±o÷	Eð 	Eà&¨%Ñ/×CÐC°F¸e±Oðr   c                ó0   € V ^8„  d   QhR\         R\        /# r   ©Ú	Exceptionr   )r   s   "r   r   r   G   s   € ÷ :ñ :œ	ð :¤cñ :r   c                 ó<   € \        V R R4      pV'       d   RV R2# R# )Ústatus_codeNzHTTP z: Ú )Úgetattr)r	   r-   s   & r   Ú_http_prefixr0   G   s&   € Ü˜% °Ó5€Kß&1ˆU�;�-˜rÐ"Ð9°rÐ9r   c                   ó¸   a € ] tR t^Lt o Rt]V 3R lR l4       t]V 3R lR l4       t]V 3R lR l4       t]V 3R lR	 l4       t	V 3R
 lR lt
V 3R lR ltRtV tR# )ÚApiErrorSummaryMixinz?Provider error -> user/log-safe summary (see module docstring).c                ób   <€ V ^8„  d   QhRS[ S[S[S[3,          ,          RS[ S[,          RS[/# )r   Úerror_contextr-   r
   )r   Údictr   r   Úintr   )r   Ú__classdict__s   "€r   r   Ú!ApiErrorSummaryMixin.__annotate__P   s6   ø€ ÷ 2ñ 2Ù¡¡S©# X¥Õ/ð2Ù>FÁs½mð2á	ñ2r   c                óâ   a € VR9  d   R# \        S \        4      '       g   R# RP                  V 3R lR 4       4      pVP                  4       '       g   R# RV9   g   RV9   d   R# \	        V4      # )uN  Detect subscription/entitlement 401/403s that masquerade as auth failures.

Refreshing a token cannot fix an unsubscribed account, so callers surface the error instead of looping
the pool. xAI returns the same permission-denied text for BOTH cases; a ``[WKE=unauthenticated:...]``
suffix (or "access token could not be validated") means stale token â†’ return False so the refresh path
runs.

Disambiguator for xAI (#29344): the same ``code`` text ("The caller does not have permission to
execute the specified operation") is returned for BOTH an unsubscribed account AND a stale OAuth
access token.  xAI ships an explicit signal in the ``error`` field that tells the two apart: a
``[WKE=unauthenticated:...]`` suffix (and/or the ``OAuth2 access token could not be validated``
phrasing) means the credentials failed validation â€” that's recoverable by refreshing the token, NOT
by surfacing an entitlement message. When either signal is present we return False eagerly so the
credential-pool refresh path runs, letting long-running TUI sessions recover from stale tokens
without an exit/reopen cycle.
FÚ c              3   óˆ   <"  € T F7  p\        SP                  V4      ;'       g    R 4      P                  4       x € K9  	  R# 5i)r.   N)r   Úgetr   )r   Úkr4   s   & €r   r   Ú?ApiErrorSummaryMixin._is_entitlement_failure.<locals>.<genexpr>h   s9   øé € ð 
Ù=c¸ŒC�×!Ñ! !Ó$×*Ð*¨Ó+×1Ñ1×3Ð3Ó=cùs
   ƒ!A¥Az[wke=unauthenticated:z*oauth2 access token could not be validated>   Né‘  é“  )ÚmessageÚreasonÚcoder	   )r   r5   ÚjoinÚstripr(   )r4   r-   Úhaystacks   f& r   Ú_is_entitlement_failureÚ,ApiErrorSummaryMixin._is_entitlement_failureO   sm   ø€ ð( Ð.Ô.ÙÜ˜-¬×.Ò.Ùà—8‘8ô 
Ù=có
ó 
ˆð �~‰~×ÒÙØ" hÔ.Ð2^ÐbjÔ2jÙÜ'¨Ó1Ð1r   c                ó&   <€ V ^8„  d   QhRS[ RS[ /# )r   Údetailr
   ©r   )r   r7   s   "€r   r   r8   r   s   ø€ ÷ 2ñ 2±ð 2¹ñ 2r   c                óz   € V '       d    \        V P                  4       4      '       g   V # RV 9   d   V # V  \         2# )u¤  Append a neutral hint when xAI's OAuth surface returns the permission-denied 403.

xAI's ``/v1/responses`` uses one body for several causes (no subscription, tier lacks the model, quota
exhausted). The least obvious: X Premium+ does NOT include API access â€” only SuperGrok does. Lead with
that, keep the raw text, point at https://grok.com/?_s=usage. Idempotent: a substring unique to the
hint marks prior decoration.
zX Premium+ does NOT include)r(   r   Ú_XAI_ENTITLEMENT_HINT)rJ   s   &r   Ú_decorate_xai_entitlement_errorÚ4ApiErrorSummaryMixin._decorate_xai_entitlement_errorq   s;   € ÷ Ô5°f·l±l³n×EÒEØˆMØ(¨FÔ2ØˆMØ�Ô/Ð0Ð1Ð1r   c                ó&   <€ V ^8„  d   QhRS[ RS[/# )r   Úvaluer
   )r   r   )r   r7   s   "€r   r   r8   �   s   ø€ ÷ ñ ©ð ±ñ r   c                ó¾  € \        V \        4      '       d   V # \        V \        4      '       d§   \         FF  pV P	                  V4      p\        V\        4      '       g   K,  VP                  4       '       g   KD  Vu # 	  \         F2  pW9   g   K  \        P                  W,          4      pV'       g   K0  Vu # 	   \        P                  ! V RRR7      # \        V \        \        34      '       d=   V  Uu. uF  p\        P                  V4      NK  	  ppRP                  R V 4       4      # V f   R# \        V 4      #   \         d    \        T 4      u # i ; iu upi )zBReturn a display-safe string for structured provider error fields.FT)Úensure_asciiÚ	sort_keysz; c              3   ó8   "  € T F  q'       g   K  Vx € K  	  R # 5ir   r'   )r   Úparts   & r   r   Ú@ApiErrorSummaryMixin._coerce_api_error_detail.<locals>.<genexpr>•   s   é € Ð<©e d³tŸTšT«eùs   ‚	�
r.   )r   r   r5   Ú_ERROR_DETAIL_KEYSr<   rE   r2   Ú_coerce_api_error_detailr   ÚdumpsÚ	TypeErrorÚlistÚtuplerD   )rQ   ÚkeyÚnestedÚnested_detailÚitemÚpartss   &     r   rY   Ú-ApiErrorSummaryMixin._coerce_api_error_detail€   s  € ô �eœS×!Ò!ØˆLÜ�eœT×"Ò"ß)�ØŸ™ 3›�Ü˜f¤c×*Ô*¨v¯|©|¯~¬~Ø!’Mñ *÷ *�Ø–<Ü$8×$QÑ$QÐRWÕR\Ó$]�Mß$‘}Ø,Ò,ñ	 *ð
"Ü—z’z %°eÀtÔLÐLô �eœd¤E˜]×+Ò+ÙUZÓ[ÑUZÈTÔ)×BÑBÀ4ÖHÑUZˆEÐ[Ø—9‘9Ñ<©eÓ<Ó<Ð<ØŠ=ÙÜ�5‹zÐøô ô "Ü˜5“zÒ!ð"üò \s   Â<D> Ã5EÄ>EÅEc                ó&   <€ V ^8„  d   QhRS[ RS[/# r   r*   )r   r7   s   "€r   r   r8   ›   s#   ø€ ÷ G\ñ G\¡Ið G\±#ñ G\r   c                ó4  a€ \        V 4      pV o\        4       pSe˜   \        S4      V9  dˆ   VP                  \        S4      4       \        ;QJ d#    V3R l\
         4       F  '       g   K   RM	  RM! V3R l\
         4       4      '       d    R# SP                  ;'       g    SP                  oK›  \        V 4      '       d   RVR,           2# \        V 4      pRV9   g   R	V9   dÒ   \        P                  ! R
V\        P                  4      pV'       d    VP                  ^4      P                  4       MRp\        P                  ! RV4      pV'       d   VRR .M. pVP                  V4       V'       d2   VP                  RVP                  ^4      P                  4        24       RP!                  V4      # \#        V 4      P$                  R8X  d   \'        VR,          4      # \)        V RR4      p\+        V\,        4      '       d•   \+        VP/                  R4      \,        4      '       d"   VP/                  R/ 4      P/                  R4      MVP/                  R4      p	V	'       d6   \0        P3                  V	4      p	\0        P5                  V V	R,           24      # \)        V RR4      p
V
Ee    \)        V
RR4      ;'       g    RP                  4       pV'       då    \8        P:                  ! V4      p\+        V\,        4      '       d¢   VP/                  R4      p\+        V\,        4      '       d>   VP/                  R4      '       d'   \'        V \        VR,          4      R,           24      # VP/                  R4      '       d'   \'        V \        VR,          4      R,           24      # \'        V VR,           24      # \0        P5                  V VR,           24      #   \6         d    Rp ELi ; i  \8        P<                  \>        3 d    Rp EL!i ; i)u³   Extract a human-readable one-liner from an API error.

Cloudflare HTML pages â†’ ``<title>``; network/DNS failures (even SDK-wrapped) â†’ offline hint; else
truncated str(error).
Nc              3   óZ   <"  € T F   q\        S4      P                  4       9   x € K"  	  R # 5ir   r   )r   r   Úcurrents   & €r   r   Ú<ApiErrorSummaryMixin._summarize_api_error.<locals>.<genexpr>§   s#   øé € Ð\Ñ@[°fœS ›\×/Ñ/Ó1Ö1Ó@[ùr   TFzhHermes can't reach the model provider. You may be offline. Check your internet connection and try again.z'Malformed provider streaming response: :Ni,  Nz	<!DOCTYPEú<htmlz<title[^>]*>([^<]+)</title>z!HTML error page (title not found)z2Cloudflare Ray ID:\s*<strong[^>]*>([^<]+)</strong>zRay u    â€” ÚGeminiAPIError:Niè  NÚbodyr	   rA   ÚresponseÚtextr.   :Niô  Néþÿÿÿ) r   ÚsetÚidÚaddr!   Ú_NETWORK_RESOLUTION_MARKERSÚ	__cause__Ú__context__r#   r0   ÚreÚsearchÚ
IGNORECASEÚgrouprE   ÚappendrD   ÚtypeÚ__name__r   r/   r   r5   r<   r2   rY   rN   r+   r   Úloadsr    r[   )r	   ÚrawÚseenÚprefixÚmÚtitleÚrayrb   rk   Úmsgrl   ÚsnippetÚpayloadÚerrrg   s   &             @r   Ú_summarize_api_errorÚ)ApiErrorSummaryMixin._summarize_api_errorš   sW  ø€ ô �%‹jˆà+0ˆÜ›ˆØÒ!¤b¨£k¸Ô&=Ø�H‰H”R˜“[Ô!ß‹sÔ\Õ@[Ó\�s�sŠsÔ\Õ@[Ó\×\Ò\ðDñð ×'Ñ'×>Ð>¨7×+>Ñ+>ŠGä)¨%×0Ò0Ø<¸SÀ½Y¸KÐHÐHä˜eÓ$ˆà˜#Ô ¨C¤Ü—	’	Ð8¸#¼r¿}¹}ÓMˆAß*+�A—G‘G˜A“J×$Ñ$Ô&Ð1TˆEÜ—)’)ÐQÐSVÓWˆCß%+�V˜C˜R�[‘M°ˆEØ�L‰L˜ÔßØ—‘˜t C§I¡I¨a£L×$6Ñ$6Ó$8Ð#9Ð:Ô;Ø—<‘< Ó&Ð&ô �‹;×ÑÐ#3Ô3Ü(¨¨U­Ó4Ð4ô �u˜f dÓ+ˆÜ�dœD×!Ò!Ü:DÀTÇXÁXÈgÓEVÔX\×:]Ò:]�$—(‘(˜7 BÓ'×+Ñ+¨IÔ6Ðcg×ckÑckÐluÓcvˆCßÜ*×CÑCÀCÓH�Ü+×KÑKÈvÈhÐWZÐ[_ÕW`ÐVaÐLbÓcÐcô ˜5 *¨dÓ3ˆØÓðÜ" 8¨V°TÓ:×@Ð@¸b×GÑGÓI�÷ ð#Ü"Ÿjšj¨Ó1�Gô ˜g¤t×,Ò,Ø!Ÿ+™+ gÓ.�CÜ! #¤t×,Ò,°·±¸×1CÒ1CÜ4¸°xÄÀCÈ	ÅNÓ@SÐTXÕ@YÐ?ZÐ5[Ó\Ð\Ø—{‘{ 9×-Ò-Ü4¸°xÄÀGÈIÕDVÓ@WÐX\Õ@]Ð?^Ð5_Ó`Ð`Ü,°¨x¸À½°Ð-GÓHÐHô $×CÑCÀvÀhÈsÐSWÍyÈkÐDZÓ[Ð[øô! ô Ø“ðûô
 ×,Ñ,¬iÐ8ô #Ø"“Gð#ús*   Ê1O" ËO" ËO6 Ï"O3Ï2O3Ï6PÐPc                ó6   <€ V ^8„  d   QhRS[ RS[S[,          /# )r   r^   r
   )r   r   r   )r   r7   s   "€r   r   r8   ä   s   ø€ ÷ 	)ñ 	)©#ð 	)±(¹3µ-ñ 	)r   c                ó®   € \        V4      '       d   \        V\        4      '       g   R # V'       g   R# \        V4      ^8:  d   R# VR,           RVRR  2# )z<entra-id-bearer>Nz***:Né   Nú...éüÿÿÿ)Úcallabler   r   Úlen)Úselfr^   s   &&r   Ú_mask_api_key_for_logsÚ+ApiErrorSummaryMixin._mask_api_key_for_logsä   sK   € ô �C�=Š=¤¨C´×!5Ò!5Ù&ßÙÜˆs‹8�rŒ>ÙØ�b•'�˜#˜c " #˜h˜ZÐ(Ð(r   c                ó&   <€ V ^8„  d   QhRS[ RS[ /# )r   Ú	error_msgr
   rK   )r   r7   s   "€r   r   r8   ï   s   ø€ ÷ 
ñ 
©cð 
±cñ 
r   c                óô   € V'       g   R# VP                  4       P                  R4      '       g   RV9   d   R# RP                  VP                  4       4      p\	        V4      ^–8”  d   VR,          R,           pV# )zOClean up error messages for user display, removing HTML content and truncating.zUnknown errorz<!DOCTYPE htmlri   z:Service temporarily unavailable (HTML error page returned)r:   :Né–   NrŒ   )rE   Ú
startswithrD   Úsplitr�   )r�   r”   Úcleaneds   && r   Ú_clean_error_messageÚ)ApiErrorSummaryMixin._clean_error_messageï   s_   € çÙ"à�?‰?Ó×'Ñ'Ð(8×9Ò9¸WÈ	Ô=QÙOØ—(‘(˜9Ÿ?™?Ó,Ó-ˆÜˆw‹<˜#ÔØ˜d•m eÕ+ˆGØˆr   r'   N)r{   Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__ÚstaticmethodrG   rN   rY   r‡   r‘   rš   Ú__static_attributes__Ú__classdictcell__)r7   s   @r   r2   r2   L   sp   ø‡ € ÙIà÷2ó ð2ðB ÷2ó ð2ð ÷ó ðð2 ÷G\ó ðG\÷R	)ð 	)÷
ö 
r   r2   )zexpected ident at linezexpected value at linez!eof while parsing a value at linez"eof while parsing a string at linez eof while parsing a list at linez#eof while parsing an object at linezkey must be a string at lineztrailing characters at lineztrailing comma at linezexpected `,` or `}` at linezexpected `,` or `]` at linezexpected `:` at linezinvalid escape at linezinvalid number at linez$found while parsing a string at line)z$temporary failure in name resolutionzname or service not knownz,nodename nor servname provided, or not knownzgetaddrinfo failedz#no address associated with hostnameznetwork is unreachable)rA   rJ   r	   rC   rz   )rŸ   r   ru   Útypingr   r   r   Úagent.redactr   r"   r#   rr   rM   rX   r(   r0   r2   r'   r   r   Ú<module>r¥      sZ   ðñó Û 	ß &Ñ &å .ð!Ð õ&_ðÐ ð2ð ð DÐ õõ:÷
mó mr   