+
    iHàj[*  ã                  óú   € R t ^ RIHt ^ RIt^ RIt^ RIHtHtHtH	t	 ]P                  ! ]4      tRtR R ltR R ltR R	 ltR
 R ltRR/R R lltRR/R R lltRtR R ltR R ltR R ltR R lt. ROtR# )uÈ  Stream diagnostics â€” per-attempt counters, exception chains, retry logging.

When a streaming request dies mid-response these helpers record WHY (which CF
edge / OpenRouter downstream served it, bytes+chunks before the drop, HTTP
status, underlying httpx error class) to ``agent.log`` in full and to the
user-facing status line compactly. ``run_agent`` keeps thin forwarders so
existing call sites and tests patching ``run_agent.<helper>`` keep working.
)ÚannotationsN)ÚAnyÚDictÚListÚOptionalc               ó   € V ^8„  d   QhRR/# )é   Úreturnúdict[str, Any]© )Úformats   "Ú6/home/ubuntu/.hermes/hermes-agent/agent/stream_diag.pyÚ__annotate__r      s   € ÷ ñ ˜.ñ ó    c                 óL   € R\         P                   ! 4       RRR^ R^ R/ RRRRR	R
/# )zkFresh per-attempt diagnostic dict; mutated in place by the streaming functions and read by the retry block.Ú
started_atÚfirst_chunk_atNÚchunksÚbytesÚheadersÚhttp_statusÚserving_providerÚfinish_reason_seenF)Útimer   r   r   Ústream_diag_initr      s<   € ð 	”d—i’i“kÐ#3°T¸8ÀQÈÐQRØ�2�} dÐ,>Àð 	˜eðð r   c               ó(   € V ^8„  d   QhRRRRRRRR/# )r   Úagentr   Údiagr
   Úhttp_responser	   ÚNoner   )r   s   "r   r   r   $   s*   € ÷ ñ ¨ð °>ð ÐRUð ÐZ^ñ r   c                ó€  € Ve   \        V\        4      '       g   R#  \        VRR4      VR&    \        VRR4      ;'       g    / p/ p\         F3  p VP                  V4      ;p'       d   \        V4      R,          WE&   K3  K5  	  WAR&   R#   \         d     Lji ; i  \         d     K\  i ; i  \         d     R# i ; i)zkSnapshot headers + HTTP status at stream open (so they survive a drop before the first chunk). Best-effort.NÚstatus_coder   r   :Néx   N)Ú
isinstanceÚdictÚgetattrÚ	ExceptionÚSTREAM_DIAG_HEADERSÚgetÚstr)r   r   r   r   ÚcapturedÚnameÚvals   &&&    r   Ústream_diag_capture_responser-   $   sÉ   € àÒ¤J¨t´T×$:Ò$:ÙðÜ% m°]ÀDÓIˆˆ]ÑðÜ˜-¨°DÓ9×?Ð?¸RˆØ#%ˆß'ˆDðØ!Ÿ+™+ dÓ+Ð+�3Ö+Ü%(¨£X¨d¥^�H“Nñ ,ñ (ð #ˆY‹øô ô Ùðûô ô Úðûô ô ÚðúsL   žB ¯B. ÁB. Á-BÁ?
B. ÂBÂBÂB+Â'B. Â*B+Â+B. Â.B=Â<B=c               ó    € V ^8„  d   QhRRRR/# )r   ÚerrorÚBaseExceptionr	   r)   r   )r   s   "r   r   r   :   s   € ÷ Rñ R =ð R°Sñ Rr   c                ó>  a€ . pT pVeX   \        V4      ^8  dH   W!9  dB   VP                  V4       \        VRR4      ;'       g    \        VRR4      pVe   W2J d   MTpK[  R R loV'       d   RP                  V3R lV 4       4      # \	        V 4      P
                  # )a!  Compact ``Outer(msg) <- Inner(msg) <- ...`` rendering, walking ``__cause__`` then ``__context__``
(deduped, max 4 deep): the OpenAI SDK wraps httpx errors so only the wrapper class is visible at
the catch site; the inner RemoteProtocolError/ConnectError/ReadError says WHY the stream died.NÚ	__cause__Ú__context__c               ó    € V ^8„  d   QhRRRR/# )r   Úer0   r	   r)   r   )r   s   "r   r   Ú-flatten_exception_chain.<locals>.__annotate__G   s   € ÷ Iñ I�-ð I Cñ Ir   c                ó  € \        V 4      P                  4       P                  R R4      p\        V4      ^Œ8”  d   VR,          R,           MTpV'       d   \	        V 4      P
                   RV R2# \	        V 4      P
                  # )Ú
Ú :NéŒ   Nõ   â€¦Ú(Ú))r)   ÚstripÚreplaceÚlenÚtypeÚ__name__)r5   Úmsgs   & r   ÚrenderÚ'flatten_exception_chain.<locals>.renderG   sg   € Ü�!‹f�l‰l‹n×$Ñ$ T¨3Ó/ˆÜ#& s£8¨c¤>ˆc�$�i˜%Ö°sˆß/2”$�q“'×"Ñ"Ð# 1 S E¨Ð+ÐH¼¸Q»×8HÑ8HÐHr   z <- c              3  ó4   <"  € T F  pS! V4      x € K  	  R # 5i©Nr   )Ú.0r5   rD   s   & €r   Ú	<genexpr>Ú*flatten_exception_chain.<locals>.<genexpr>L   s   øé € Ð/©$ Q‘v˜a—y�y«$ùs   ƒ)r@   Úappendr%   ÚjoinrA   rB   )r/   ÚseenÚlinkÚnxtrD   s   &   @r   Úflatten_exception_chainrP   :   sŽ   ø€ ð !#€DØ$)€DØ
Ò
œs 4›y¨1œ}°Ô1AØ�‰�DÔÜ�d˜K¨Ó.×TÐT´'¸$ÀÈtÓ2TˆØŠ;˜#›+ØØŠõI÷
 48ˆ6�;‰;Ô/©$Ó/Ó/ÐQ¼TÀ%»[×=QÑ=QÐQr   c               ó    € V ^8„  d   QhRRRR/# )r   r   úOptional[dict[str, Any]]r	   Útupler   )r   s   "r   r   r   O   s   € ÷ qñ qÐ/ð q°Eñ qr   c                óª  € ^ ;rRpR;p;p;rgRp\        V \        4      '       Ed™    \        P                  ! 4       p	\        V P	                  R4      ;'       g    ^ 4      p\        V P	                  R4      ;'       g    ^ 4      p\        V P	                  R4      ;'       g    T	4      p
\        RWš,
          4      pV P	                  R4      pVe!   \        R\        V4      V
,
          4      R R	2pV P	                  R
4      ;'       g    / p\        V\        4      '       d/   V'       d'   RP                  R VP                  4        4       4      pV P	                  R4      e   \        V P	                  R4      4      pV P	                  R4      '       d   \        V R,          4      p\        V P	                  R4      4      pWaW#WGW…3#   \         d     Li ; i)z‡(http_status, bytes, chunks, elapsed, ttfb, serving_provider, finish_reason_seen, upstream)
for the retry log line; ``-`` when unknown.ç        Ú-Fr   r   r   r   z.2fÚsr   r9   c              3  ó4   "  € T F  w  rV R V 2x € K  	  R# 5i)Ú=Nr   )rH   ÚkÚvs   &  r   rI   Ú_diag_fields.<locals>.<genexpr>b   s   é € Ð(PÁ¹¸¨A¨3¨a°¨s­Ãùs   ‚r   r   r   )r#   r$   r   Úintr(   ÚfloatÚmaxrL   Úitemsr)   Úboolr&   )r   Ú_bytesÚ_chunksÚ_elapsedÚ_ttfbÚ_headers_reprÚ_http_statusÚ_serving_providerÚ_finish_reason_seenÚ_nowÚ_startedÚ_firstr   s   &            r   Ú_diag_fieldsrm   O   s–  € ð Ð€FØ€HØ?BÐB€EÐBˆMÐB˜LØÐÜ�$œ×Óð	Ü—9’9“;ˆDÜ˜Ÿ™ 'Ó*×/Ð/¨aÓ0ˆFÜ˜$Ÿ(™( 8Ó,×1Ð1°Ó2ˆGÜ˜TŸX™X lÓ3×;Ð;°tÓ<ˆHÜ˜3 ¥Ó0ˆHØ—X‘XÐ.Ó/ˆFØÒ!Ü˜s¤E¨&£M°HÕ$<Ó=¸cÐBÀ!ÐD�Ø—h‘h˜yÓ)×/Ð/¨RˆGÜ˜'¤4×(Ò(¯WØ #§¡Ñ(PÀÇÁÄÓ(PÓ P�Ø�x‰x˜Ó&Ò2Ü" 4§8¡8¨MÓ#:Ó;�Ø�x‰xÐ*×+Ò+Ü$'¨Ð-?Õ(@Ó$AÐ!Ü"& t§x¡xÐ0DÓ'EÓ"FÐð  °EÐNaÐpÐpøô ô 	Ùð	ús7   §1G Á#G Á=#G Â!A%G Ä G Ä(A)G Æ,G ÇGÇGr   c               ó8   € V ^8„  d   QhRRRRRRRRR	RR
RRRRR/# )r   r   r   Úkindr)   r/   r0   Úattemptr]   Úmax_attemptsÚmid_tool_callra   r   rR   r	   r   r   )r   s   "r   r   r   m   sX   € ÷ "Dñ "DØð"DØð"DØ%2ð"DØ=@ð"DØPSð"Dàð"Dà7ð"Dð 
ñ"Dr   c               óz  €   V P                  V4      pV'       d!   \        V4      ^ð8”  d   VR,          R,           p \	        V4      p\        P                  ! RYT\        V RR4      ;'       g    R\        V R^ 4      V P                  ;'       g    RV P                  ;'       g    R\        V4      P                  Wx.\        V4      O5RR	V//  R#   \         d    \        T4      p LÖi ; i  \         d    \        T4      P                  p LÈi ; i  \         d    \        P                  R
RR7        R# i ; i)u;  Structured WARNING to ``agent.log`` for a transient stream drop + retry, always logged regardless of
UI verbosity. With *diag*, also records upstream headers, HTTP status, bytes/chunks, elapsed and TTFB on
the dying attempt â€” enough to tell "one CF edge / downstream provider" from "random across runs".

The ``serving_provider`` field names the downstream that actually served the attempt (relays re-roll it
per request and report it only in the chunk body), so a drop can be attributed to a provider even when
the response carried no ``x-openrouter-provider`` header.:Néð   Nr;   uè   Stream %s on attempt %s/%s â€” retrying. subagent_id=%s depth=%s provider=%s base_url=%s error_type=%s error=%s chain=%s http_status=%s bytes=%d chunks=%d elapsed=%.2fs ttfb=%s serving_provider=%s finish_reason_seen=%s upstream=[%s]Ú_subagent_idNrV   Ú_delegate_depthÚextrarr   zstream-retry log emit failedT)Úexc_info)Ú_summarize_api_errorr&   r)   r@   rP   rA   rB   ÚloggerÚwarningr%   ÚproviderÚbase_urlrm   Údebug)	r   ro   r/   rp   rq   rr   r   Ú_summaryÚ_chains	   &$$$$$$  r   Úlog_stream_retryr�   m   s-  € ðDð	"Ø×1Ñ1°%Ó8ˆH÷ œ˜H›¨Ô+Ø •~¨Õ-ˆHð	*Ü,¨UÓ3ˆFô 	�ŠðFð ˜<Ü�E˜>¨4Ó0×7Ð7°C¼ÀÐHYÐ[\Ó9]Ø�N‰N×!Ð!˜c 5§>¡>×#8Ð#8°SÜ�‹K× Ñ  (ð		
ô 6BÀ$Ó5Gò		
ð # MÐ2ô		
øô ô 	"Ü˜5“zŠHð	"ûô ô 	*Ü˜%“[×)Ñ)ŠFð	*ûô ô DÜ�‰Ð3¸dˆ×CðDúsh   ƒC ”D œ D ½C. Á&D Á/ D ÂD Â%+D ÃC+Ã(D Ã*C+Ã+D Ã. DÄD ÄDÄD Ä"D:Ä9D:c               ó4   € V ^8„  d   QhRRRRRRRRRR	R
RRR/# )r   r   r   r/   r0   rp   r]   rq   rr   ra   r   rR   r	   r   r   )r   s   "r   r   r   ’   sF   € ÷ ñ ØðØ'ðØ25ðØEHðàðà7ðð 
ñr   c               ó@  € V'       d   RMRp\        WWW4VR7       V P                  ;'       g    RpRp \        V\        4      '       d   VP	                  R4      MRp	V	e5   R\        R	\        P                  ! 4       \        V	4      ,
          4      R
 R2p T P                  RT RT R\        T4      P                   RT RT RT R24       T P                  RT RT R\        T4      P                   24       R#   \         d     Lti ; i  \         d     R# i ; i)zÐOne compact user-visible status line for a stream drop+retry, plus the full WARNING via log_stream_retry.
``after Xs`` distinguishes "couldn't connect" (0s) from "died mid-stream" (idle-kill / proxy timeout).zdrop mid tool-callÚdrop)ro   r/   rp   rq   rr   r   r|   Ú r   Nú after rU   z.1frW   u   âš ï¸� z stream z (r=   u    â€” attempt Ú/z dropped, reconnectingzstream retry )r�   r|   r#   r$   r(   r_   r   r^   r&   Ú_buffer_diagnostic_statusrA   rB   Ú_touch_activity)
r   r/   rp   rq   rr   r   ro   r|   Ú_suffixÚstarteds
   &$$$$$    r   Úemit_stream_droprŒ   ’   s-  € ÷ $1Ñ°f€DÜØ À\Ðuyõð �~‰~×+Ð+ €HØ€GðÜ,6°t¼T×,BÒ,B�$—(‘(˜<Ô(ÈˆØÒØ¤ C¬¯ª«´u¸W³~Õ)EÓ FÀsÐKÈ1ÐMˆGðØ×'Ñ'Ø�h�Z˜x¨ v¨R´°U³×0DÑ0DÐ/EÀQÀwÀið PØ"˜) 1 \ NÐ2HðJô	
ð 	×Ñ ¨g¨Y°a¸°~ÀWÌTÐRWË[×MaÑMaÐLbÐcÖdøô ô Ùðûô ô Úðús%   µA!C= ÂA$D Ã=DÄ
DÄDÄDc               ó    € V ^8„  d   QhRRRR/# )r   r/   r0   r	   r   r   )r   s   "r   r   r   ´   s   € ÷ ñ ˜=ð ¨Sñ r   c                óÎ   € T p\        ^4       F@  pVf    R#  \        VRR4      pVe   Vu # VP                  ;'       g    VP                  pKB  	  R#   \         d    Rp L=i ; i)zfThe buffered ``httpx.Request`` carried by the exception chain (SDK wrapper or httpx error), else None.NÚrequest)Úranger%   ÚRuntimeErrorr2   r3   )r/   rN   Ú_r�   s   &   r   Ú_failed_requestr“   ´   so   € à$)€DÜ�1ŽXˆØŠ<Úð	Ü˜d I¨tÓ4ˆGð ÒØŠNØ�~‰~×1Ð1 ×!1Ñ!1Šñ ñ øô ô 	ØŠGð	ús   ™AÁA$Á#A$c               ó    € V ^8„  d   QhRRRR/# )r   r�   r   r	   zOptional[int]r   )r   s   "r   r   r   Ä   s   € ÷ ñ  ð ¨ñ r   c                óØ   € \        V R R4      p\        V\        4      '       d   \        VP	                  R4      4      # \        V\
        \        \        34      '       d   \        V4      # R# )ÚcontentNzutf-8)r%   r#   r)   r@   Úencoder   Ú	bytearrayÚ
memoryview)r�   r–   s   & r   Ú_request_body_bytesrš   Ä   sR   € Ü�g˜y¨$Ó/€GÜ�'œ3×ÒÜ�7—>‘> 'Ó*Ó+Ð+Ü�'œE¤9¬jÐ9×:Ò:Ü�7‹|ÐÙr   c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   r/   r0   Úattemptsr]   r}   r   r	   r)   r   )r   s   "r   r   r   Í   s/   € ÷ Pñ P Mð PÀð PÈsð PÐWZñ Pr   c          	     óŒ  € ^ RI Hp \        V 4      pT! \        \	        VRR4      ;'       g    T;'       g    R4      4      P
                  ;'       g    Rp\        V4      pRT RT RV^8w  d   R	MR 2pVf
   VR
,           # VR\        ^\        VR,          4      4       R2,          pV\        8¼  d
   VR,           # VR
,           # )zòThe one user-facing line for "no stream event ever arrived and the connect retries are spent":
names the host, the attempt count and the serialized request size so a body-size limit is
distinguishable from an outage without reading agent.log.)ÚurlparseÚurlNr…   zthe endpointu   â�Œ Could not open a stream to r†   z attemptrW   u;   ; the endpoint looks unreachable â€” try again in a moment.z
 (request i   z KB)zH; the endpoint or a proxy in front of it may reject requests this large.)
Úurllib.parserž   r“   r)   r%   Úhostnamerš   r_   ÚroundÚLARGE_REQUEST_HINT_BYTES)r/   rœ   r}   rž   r�   ÚhostÚsizeÚlines   &$$     r   Úconnect_exhausted_noticer§   Í   sÍ   € õ &Ü˜eÓ$€GÙ”Cœ ¨°Ó5×GÐG¸×GÐGÀRÓHÓI×RÑR×dÐdÐVd€DÜ˜wÓ'€DØ,¨T¨F°'¸(¸À8ÐS[Ð_`ÔS`ÉCÐfhÐKiÐj€DØ‚|ØÐSÕSÐSØˆjœ˜Q¤ d¨T¥kÓ 2Ó3Ð4°DÐ9Õ9€DØÔ'Ô'ØÐ`Õ`Ð`ØÐOÕOÐOr   c          
     ó,   € V ^8„  d   QhRRRRRRRRRR	/# )
r   r   r   r/   r0   rœ   r]   r}   r	   r   r   )r   s   "r   r   r   Þ   s2   € ÷ *ñ *¨3ð *°}ð *ÐSVð *Ðbeð *Ðjnñ *r   c               ó  a€ \        WVR7      o\        ;QJ d4    V3R l\        V RR4      ;'       g    R 4       F  '       g   K   RM)	  RM%! V3R l\        V RR4      ;'       g    R 4       4      '       d   R# V P                  S4       R# )zÂBuffer :func:`connect_exhausted_notice` once per turn: the outer retry/fallback loop re-enters the
stream call several times, and every pass exhausting the same budget must not add another copy.)rœ   r}   c              3  óD   <"  € T F  w  r\        V4      S8H  x € K  	  R # 5irG   )r)   )rH   Ú_kindrC   Útexts   &  €r   rI   Ú2buffer_connect_exhausted_notice.<locals>.<genexpr>â   s   øé € Ð
aÑ.`¡
 Œ3ˆs‹8�tÖÓ.`ùs   ƒ Ú_retry_status_bufferNTFr   )r§   Úanyr%   rˆ   )r   r/   rœ   r}   r¬   s   &&$$@r   Úbuffer_connect_exhausted_noticer°   Þ   sq   ø€ ô $ EÀxÔP€Dß
ƒsÔ
a¬g°eÐ=SÐUYÓ.Z×.`Ð.`Ð^`Ð.`Ó
a‡s‡s‚sÔ
a¬g°eÐ=SÐUYÓ.Z×.`Ð.`Ð^`Ð.`Ó
a×aÒaÙØ	×#Ñ# DÖ)r   )
zcf-rayzcf-cache-statuszx-openrouter-providerzx-openrouter-modelzx-openrouter-idzx-request-idzx-vercel-idÚviaÚserverzx-forwarded-fori   )r'   r°   r§   rŒ   rP   r�   r-   r   )Ú__doc__Ú
__future__r   Úloggingr   Útypingr   r   r   r   Ú	getLoggerrB   rz   r'   r   r-   rP   rm   r�   rŒ   r£   r“   rš   r§   r°   Ú__all__r   r   r   Ú<module>r¹      sŠ   ðñõ #ã Û ß ,Ó ,à	×	Ò	˜8Ó	$€ðÐ õõõ,Rõ*qð<"Dà:>÷"DðJà:>÷ð> &Ð õõ õPõ"*ò	‚r   