+
    kHàjƒT  ã                  ó6  € R t ^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RI	H
t
HtHt ]P                  ! R4      tRtRtRtR	tR
tRt^UtRtRtRt ! R R]4      t] ! R R4      4       t ! R R4      t ! R R4      tR R ltR R ltR R lt  ! R R4      t!R# )zÍWeCom native streaming mixin (``msgtype: stream`` via aibot_respond_msg): per-turn state, per-req_id
ack tracking (official replyStreamNonBlocking semantics), keep-alive heartbeat, finalize clock fallback.)ÚannotationsN)Ú	dataclass)ÚAnyÚDictÚOptionalzplugins.platforms.wecom.adapterÚaibot_respond_msgië ië ië ip  i P  g      t@g      ^@Fc                  ó:   a € ] tR t^%tRt]R3R V 3R llltRtV ;t# )ÚWeComStreamExpiredErrorzgRaised on errcode 846608/846604: the stream/req_id reply flow is dead; fall back to ``aibot_send_msg``.Ú c               ó    € V ^8„  d   QhRRRR/# )é   ÚerrcodeÚintÚerrmsgÚstr© )Úformats   "ÚF/home/ubuntu/.hermes/hermes-agent/plugins/platforms/wecom/streaming.pyÚ__annotate__Ú$WeComStreamExpiredError.__annotate__(   s   € ÷ 4ñ 4 ð 4Àcñ 4ó    c                	ób   <€ \         ST `  R T RT;'       g    R 24       WuV n        V n        R# )zWeCom stream expired (errcode=z): z	no detailN)ÚsuperÚ__init__r   r   )Úselfr   r   Ú	__class__s   &&&€r   r   Ú WeComStreamExpiredError.__init__(   s6   ø€ Ü‰ÑÐ9¸'¸À#Àf×F[ÐF[ÐP[ÐE\Ð]Ô^Ø$+Ð!ˆŒ�d–kr   ©r   r   )	Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__ÚSTREAM_EXPIRED_ERRCODEr   Ú__static_attributes__Ú__classcell__)r   s   @r   r	   r	   %   s   ø† Ùqà&<ÈB÷ 4÷ 4ð 4r   r	   c                  óL   € ] tR t^-t$ RtR]R&   R]R&   RtR]R&   R	tR
]R&   RtR	# )Ú
ReplyFramezCA reply frame awaiting its aibot_respond_msg ack (FIFO per req_id).údict[str, Any]Úbodyzasyncio.FutureÚfutureFÚboolÚis_finalNúOptional[float]Úsent_atr   )	r   r   r    r!   r"   Ú__annotations__r,   r.   r$   r   r   r   r'   r'   -   s%   ‡ áMØ
ÓØÓØ€HˆdÓØ#€Gˆ_×#r   r'   c                  ó&   € ] tR t^6tRtR R ltRtR# )Ú
ReplyQueuezXPer-req_id pending-ack tracker: intermediates skip while an ack is pending, finals wait.c               ó   € V ^8„  d   QhRR/# )r   Úreq_idr   r   )r   s   "r   r   ÚReplyQueue.__annotate__8   s   € ÷ 5ñ 5˜sñ 5r   c                	ó$   € VR uV n         V n        R # ©N)r3   Úpending_ack)r   r3   s   &&r   r   ÚReplyQueue.__init__8   s   € Ø(.°Ð%ˆŒ�TÖ%r   )r7   r3   N©r   r   r    r!   r"   r   r$   r   r   r   r1   r1   6   s   † Ùb÷5ñ 5r   r1   c                  ó&   € ] tR t^<tRtR R ltRtR# )Ú
StreamTurnzBPer-turn stream state so concurrent messages never share a stream.c               ó    € V ^8„  d   QhRRRR/# )r   Úchat_idr   r3   r   )r   s   "r   r   ÚStreamTurn.__annotate__>   s   € ÷ Dñ D ð D¨Sñ Dr   c                	ó  € WR \         P                  ! 4       P                  R,           2uV n        V n        V n        RV n        R;V n        ;V n        V n	        \        P                  ! 4       V n        RV n        ^ V n        RV n        R# )Ústream_:Né   Nr
   FN)ÚuuidÚuuid4Úhexr=   r3   Ú	stream_idÚaccumulated_textÚ	finalizedÚseededÚexpiredÚtimeÚ	monotonicÚ
start_timeÚlast_sent_contentÚ_intermediate_frames_sentÚkeepalive_handle)r   r=   r3   s   &&&r   r   ÚStreamTurn.__init__>   ss   € Ø4;ÀwÌtÏzÊzË|×O_ÑO_Ð`cÕOdÐNeÐEfÐ1ˆŒ�d”k 4¤>Ø "ˆÔØ6;Ð;ˆŒÐ;˜œ t¤|ÜŸ.š.Ó*ˆŒØ&(ˆÔØ./ˆÔ&Ø?CˆÖr   )rN   rF   r=   rI   rG   rO   rM   r3   rH   rL   rE   Nr9   r   r   r   r;   r;   <   s   † ÙL÷Dñ Dr   r;   c               ó    € V ^8„  d   QhRRRR/# )r   r)   r(   Úreturnr   )r   s   "r   r   r   H   s   € ÷ Rñ R�^ð R¨ñ Rr   c                ót   € \        V P                  R 4      \        4      '       d   V P                  R / 4      # / # )Ústream)Ú
isinstanceÚgetÚdict)r)   s   &r   Ú
_stream_ofrX   H   s-   € Ü%/°·±¸Ó0BÄD×%IÒ%Iˆ4�8‰8�H˜bÓ!ÐQÈrÐQr   c               ó    € V ^8„  d   QhRRRR/# )r   r)   r(   rR   Útupler   )r   s   "r   r   r   L   s   € ÷ @ñ @�~ð @¨%ñ @r   c                ó`   € \        V 4      pVP                  R R4      VP                  RR4      3# )ÚidúN/AÚfinish)rX   rV   )r)   rT   s   & r   Ú_stream_descr_   L   s-   € Ü˜Ó€FØ�:‰:�d˜EÓ" F§J¡J¨x¸Ó$?Ð?Ð?r   c               ó    € V ^8„  d   QhRRRR/# )r   Úsincer-   rR   Úfloatr   )r   s   "r   r   r   Q   s   € ÷ :ñ :�Oð :¨ñ :r   c                ót   € \         P                  ! 4       T ;'       g    \         P                  ! 4       ,
          # r6   )rJ   rK   )ra   s   &r   Ú_elapsedrd   Q   s#   € Ü�>Š>Ó˜u×8Ð8¬¯ªÓ(8Õ9Ð9r   c                  ój  € ] tR t^UtRt]tRtRRRR/R R lltR R	 ltR
 R lt	R R lt
R R ltR R lt]R R l4       tR R ltR R ltR R ltR R ltR R ltR R lt]R  R! l4       tR6R" R# lltR$RR%R&R'R&/R( R) lltR* R+ ltR, R- ltR'R&R$RR.R&/R/ R0 lltR7R1 R2 lltR8R3 R4 lltR5tR&# )9ÚWeComStreamMixinzfNative streaming mixed into WeComAdapter (uses its ws transport, registries and ``_stream_*`` config).g      .@r,   FÚskip_if_pendingc          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r   Úreply_req_idr   r)   r(   r,   r+   rg   rR   r   )r   s   "r   r   ÚWeComStreamMixin.__annotate__[   s:   € ÷ $<ñ $<°Sð $<Àð $<Ð]að $<ð  }Að $<ð  N\ñ $<r   c          	   ƒ  óÜ  "  € V P                  4        V P                  V4      pV P                  P                  V\	        V4      4      pV'       d   VP
                  e	   RRR^ RR/# V'       d(   VP
                  e   V P                  We4      G Rj  x€L
  \        P                  ! 4       P                  4       p\        W'V\        P                  ! 4       R7      pW`P                  V&   W†n        \        P                  ! RV P                  WSV.\!        V4      O\#        \%        V4      P'                  R	R
4      ;'       g    R
4      N5!    V P)                  R\*        RRV/RV/4      G Rj  x€L
  T'       g   R^ RR/#  \        P4                  ! YpP6                  R7      G Rj  x€L
 T P/                  YeT4       #  EL) LQ  \,         d;    T P/                  YeT4       TP1                  4       '       g   TP3                  4        h i ; i Lc  \8         d?    \        P;                  RT P                  T4       R^ RRRR/u T P/                  YeT4       # i ; i  T P/                  YeT4       i ; i5i)z°aibot_respond_msg with per-req_id ack tracking: is_final drains the pending ack then awaits its own;
skip_if_pending returns ``{"skipped": True}`` while a prior ack is pending.NÚskippedTr   r   r7   )r)   r*   r,   r.   zg[%s] _send_reply_queued: req_id=%s is_final=%s skip_if_pending=%s stream_id=%s finish=%s content_len=%dÚcontentr
   ÚcmdÚheadersr3   r)   Úsent_nonblocking©Útimeoutuˆ   [%s] Final frame ack timeout (req_id=%s) â€” treating as delivered (matches official wecom-openclaw-plugin behaviour). No fallback send.Úack_timeout_assumed_deliveredÚack_pending)Ú_require_wsÚ_require_reply_req_idÚ_reply_queuesÚ
setdefaultr1   r7   Ú_drain_pending_ackÚasyncioÚget_running_loopÚcreate_futurer'   rJ   rK   ÚloggerÚdebugÚnamer_   ÚlenrX   rV   Ú
_send_jsonÚAPP_CMD_RESPONSEÚ	ExceptionÚ_release_pendingÚdoneÚcancelÚwait_forÚ_REPLY_ACK_TIMEOUTÚTimeoutErrorÚwarning)	r   ri   r)   r,   rg   Ú
normalizedÚqueuer*   Úframes	   &&&$$    r   Ú_send_reply_queuedÚ#WeComStreamMixin._send_reply_queued[   sž  é € ð 	×ÑÔØ×/Ñ/°Ó=ˆ
Ø×"Ñ"×-Ñ-¨j¼*ÀZÓ:PÓQˆß˜u×0Ñ0Ò<Ø˜t Y°°8¸]ÐKÐKß˜×)Ñ)Ò5Ø×)Ñ)¨%Ó<×<Ð<Ü!(×!9Ò!9Ó!;×!IÑ!IÓ!KˆÜ ¸hÔPT×P^ÒP^ÓP`Ôaˆð */×Ñ˜:Ñ&Ø!ÔÜ�ŠØuÐw{÷  xAñ  xAð  CMð  Yhð	
ô kwð  x|ó  k}ð	
ô Bô  CMð  NRó  CS÷  CWñ  CWð  Xað  ceó  Cf÷  Clð  Clð  jló  mô	
ð	Ø—/‘/ 5Ô*:¸IÈÐR\ÐG]Ð_eÐgkÐ"lÓm×mÐm÷ Ø˜q (Ð,>Ð?Ð?ð	<Ü ×)Ò)¨&×:QÑ:QÔR×Rð ×!Ñ! %°UÕ;ò7 =ñ nøÜô 	à×!Ñ! %°UÔ;Ø—;‘;—=’=Ø—‘”Øð	úñ SøÜô 	bä�N‰Nð  fð  hl÷  hqñ  hqð  s}ô  ~Ø˜q (Ð,KÈ]Ð\`ÐaÑaà×!Ñ! %°UÕ;ð	bûð
 ×!Ñ! %°UÕ;üs’   ‚A,I,Á/"I,ÂF:ÂB8I,Å F? Å+F=Å,F? Å0I,Å8I,Å?$H	 Æ#HÆ$H	 Æ'I,Æ=F? Æ?AHÈI,ÈH	 È	4IÈ=I È>I,ÉIÉI ÉI)É)I,c               ó$   € V ^8„  d   QhRRRRRR/# )r   rŒ   r1   r3   r   rR   ÚNoner   )r   s   "r   r   rj   �   s!   € ÷ !ñ !¨jð !À#ð !È$ñ !r   c              ƒ  ó   "  € VP                   pV P                  V.\        VP                  4      O5p\        P
                  ! R.VO\        VP                  4      N5!    \        P                  ! \        P                  ! VP                  4      V P                  R7      G Rj  x€L
  RVn         R#  L  \         d1    \        P                  ! R.TO\        TP                  4      N5!    LE\         d     LQi ; i5i)zWBefore a final frame: wait (bounded) for the pending intermediate's ack, then clear it.u‹   [%s] _send_reply_queued: final waiting for pending ack drain â€” req_id=%s pending_stream_id=%s pending_finish=%s pending_sent_at=%.1fs_agorq   Nu¾   [%s] Reply ack timeout waiting for pending (req_id=%s) â€” pending_stream_id=%s pending_finish=%s elapsed=%.1fs. Possible causes: ack cmd filtered, ack req_id mismatch, or WeCom did not ack.)r7   r   r_   r)   r}   r~   rd   r.   rz   r‡   Úshieldr*   rˆ   r‰   rŠ   rƒ   )r   rŒ   r3   Úpending_frameÚpending_descs   &&&  r   ry   Ú#WeComStreamMixin._drain_pending_ack�   s   é € à×)Ñ)ˆØŸ	™	 6ÐM¬L¸×9KÑ9KÓ,LÑMˆÜ�Šð  cð  	Tð  frð  	Tô  t|ð  }J÷  }Rñ  }Ró  tSô  	Tð	Ü×"Ò"¤7§>¢>°-×2FÑ2FÓ#GÐQU×QhÑQhÔi×iÐið !ˆÖñ jøÜô 	Ü�NŠNð Qðàðä'¨×(=Ñ(=Ó>öô ô 	Ùð	üsO   ‚AC>Á!AB4 Â$B2Â%B4 Â)	C>Â2B4 Â48C;Ã,C>Ã.C;Ã7C;Ã8C>Ã:C;Ã;C>c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   rŒ   r1   r3   r   r�   r'   rR   r‘   r   )r   s   "r   r   rj   ‘   s)   € ÷ 1ñ 1 jð 1¸#ð 1Àjð 1ÐUYñ 1r   c                óŒ   € VP                   VJ d   RVn         VP                   f   V P                  P                  VR4       R# R# )zJClear ``frame`` if it is still the pending ack; drop the queue once empty.N)r7   rw   Úpop)r   rŒ   r3   r�   s   &&&&r   r„   Ú!WeComStreamMixin._release_pending‘   s?   € à×Ñ Ó%Ø $ˆEÔØ×ÑÒ$Ø×Ñ×"Ñ" 6¨4Ö0ñ %r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r3   r   Úpayloadr(   rR   r+   r   )r   s   "r   r   rj   ˜   s!   € ÷ ñ ¨ð °~ð È$ñ r   c                ó(  € V P                   P                  V4      pVe   VP                  f   R# VP                  pVP                  P	                  4       '       g¥   \        VP                  R4      \        4      '       d   VP                  R/ 4      M/ p\        P                  RV P                  WP                  \        VP                  4      VP                  RR4      4       VP                  P                  V4       V P                  W1V4       R# )z5Resolve a pending reply ack. Returns True if handled.Fr)   zP[%s] _resolve_reply_ack: resolved req_id=%s is_final=%s elapsed=%.2fs errcode=%sr   r]   T)rw   rV   r7   r*   r…   rU   rW   r}   r~   r   r,   rd   r.   Ú
set_resultr„   )r   r3   rœ   rŒ   r�   Ú_bodys   &&&   r   Ú_resolve_reply_ackÚ#WeComStreamMixin._resolve_reply_ack˜   s  € à×"Ñ"×&Ñ& vÓ.ˆØŠ=˜E×-Ñ-Ò5ÙØ×!Ñ!ˆØ�|‰|× Ñ ×"Ò"Ü/9¸'¿+¹+ÀfÓ:MÌt×/TÒ/T�G—K‘K ¨Ô+ÐZ\ˆEÜ�L‰LÐkÐmq×mvÑmvÐx~÷  AOñ  AOô  QYð  Z_÷  Zgñ  Zgó  Qhð  jo÷  jsñ  jsð  t}ð  Dó  jEô  FØ�L‰L×#Ñ# GÔ,Ø×Ñ˜e¨UÔ3Ùr   c               ó    € V ^8„  d   QhRRRR/# )r   Úerrorrƒ   rR   r‘   r   )r   s   "r   r   rj   ¥   s   € ÷ #ñ #¨	ð #°dñ #r   c                	óX  € \        V P                  P                  4       4       Fh  pVP                  '       g   K  VP                  P                  P                  4       '       d   KC  VP                  P                  P                  V4       Kj  	  V P                  P                  4        R # r6   )Úlistrw   Úvaluesr7   r*   r…   Úset_exceptionÚclear)r   r£   rŒ   s   && r   Ú_fail_reply_queuesÚ#WeComStreamMixin._fail_reply_queues¥   st   € Ü˜$×,Ñ,×3Ñ3Ó5Ö6ˆEØ× × Ò ¨×):Ñ):×)AÑ)A×)FÑ)F×)HÔ)HØ×!Ñ!×(Ñ(×6Ñ6°uÖ=ñ 7ð 	×Ñ× Ñ Ö"r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r=   r   Úreply_toúOptional[str]rR   r   )r   s   "r   r   rj   «   s&   € ÷ {ñ {¨cð {¸]ð {È}ñ {r   c                óÀ   € V P                  V4      ;'       gG    V P                  P                  \        T;'       g    R4      P	                  4       4      ;'       g    R# )uX   Explicit ``reply_to`` (cached message id) â†’ last inbound req_id for the chat â†’ None.r
   N)Ú_reply_req_id_for_messageÚ_last_chat_req_idsrV   r   Ústrip)r   r=   r¬   s   &&&r   Ú_resolve_stream_req_idÚ'WeComStreamMixin._resolve_stream_req_id«   sN   € à×-Ñ-¨hÓ7×zÐz¸4×;RÑ;R×;VÑ;VÔWZÐ[b×[hÐ[hÐfhÓWi×WoÑWoÓWqÓ;r×zÐzÐvzÐzr   c               ó    € V ^8„  d   QhRRRR/# )r   Úturnr;   rR   r‘   r   )r   s   "r   r   rj   °   s   € ÷ ñ  
ð ¨tñ r   c                	ó~   € V P                   R uqn         Ve    VP                  4        R # R #   \         d     R # i ; ir6   )rO   r†   rƒ   )rµ   Úhandles   & r   Ú_cancel_keepaliveÚ"WeComStreamMixin._cancel_keepalive¯   sB   € à(,×(=Ñ(=¸tÐ%ˆÔ%ØÒðØ—‘–ñ øô ô Úðús   ™- ­<»<c               ó$   € V ^8„  d   QhRRRRRR/# ©r   rµ   r;   Úturn_idr­   rR   r‘   r   )r   s   "r   r   rj   ¸   s&   € ÷ Qñ Q ð Q°mð QÈñ Qr   c                ó¦   € V P                  V4       V P                  P                  VP                   RT;'       g    VP                   2R4       R# )zXSingle choke point for "turn is dead": cancel the timer, then drop it from the registry.Ú:N)r¸   Ú_stream_turnsr™   r=   r3   ©r   rµ   r¼   s   &&&r   Ú_retire_turnÚWeComStreamMixin._retire_turn¸   sB   € à×Ñ˜tÔ$Ø×Ñ×Ñ $§,¡, ¨q°×1GÐ1G¸D¿K¹KÐ0HÐIÈ4ÖPr   c               ó$   € V ^8„  d   QhRRRRRR/# r»   r   )r   s   "r   r   rj   ½   s!   € ÷ 5ñ 5 ð 5°mð 5Èñ 5r   c                	ó€   € R Vn         V P                  W4       V P                  P                  VP                  4       R# )TN)rI   rÁ   Ú_stream_expired_chatsÚaddr=   rÀ   s   &&&r   Ú_expire_turnÚWeComStreamMixin._expire_turn½   s/   € ØˆŒØ×Ñ˜$Ô(Ø×"Ñ"×&Ñ& t§|¡|Ö4r   c               ó    € V ^8„  d   QhRRRR/# )r   r=   r   rR   úOptional[StreamTurn]r   )r   s   "r   r   rj   Â   s   € ÷ pñ p°#ð pÐ:Nñ pr   c                	ó`   a€ \        V3R  lV P                  P                  4        4       R4      # )c              3  ót   <"  € T F-  qP                   S8X  g   K  VP                  '       d   K)  Vx € K/  	  R # 5ir6   )r=   rG   )Ú.0Útr=   s   & €r   Ú	<genexpr>Ú>WeComStreamMixin._find_active_turn_for_chat.<locals>.<genexpr>Ã   s)   øé € ÐhÑ ;˜1¿y¹yÈGÑ?S”QÐ\]×\gÕ\g—Q’QÓ ;ùs   ƒ8š8®
8N)Únextr¿   r¦   )r   r=   s   &fr   Ú_find_active_turn_for_chatÚ+WeComStreamMixin._find_active_turn_for_chatÂ   s&   ø€ ÜÔh × 2Ñ 2× 9Ñ 9Ô ;ÓhÐjnÓoÐor   c               ó$   € V ^8„  d   QhRRRRRR/# r»   r   )r   s   "r   r   rj   Å   s!   € ÷ ñ  :ð ¸=ð ÈTñ r   c               ó6  € V P                   '       d3   VP                  '       g!   VP                  '       g   VP                  e   R#  \        P
                  ! 4       P                  V P                  V P                  W4      Vn        R#   \         d     R# i ; i)zGArm the keep-alive timer if enabled and not already armed (idempotent).N)
Ú_stream_keepalive_enabledrG   rI   rO   rz   r{   Ú
call_laterÚ"_stream_keepalive_interval_secondsÚ_on_keepalive_fireÚRuntimeErrorrÀ   s   &&$r   Ú_arm_keepaliveÚWeComStreamMixin._arm_keepaliveÅ   s�   € à×-×-Ð-°··°À4Ç<Ç<À<ÐSW×ShÑShÒStÙð	Ü$+×$<Ò$<Ó$>×$IÑ$IÈ$×JqÑJqÐsw÷  tKñ  tKð  MQó  %[ˆDÖ!øÜô 	Úð	ús   Á?B	 Â	BÂBc               ó$   € V ^8„  d   QhRRRRRR/# r»   r   )r   s   "r   r   rj   Î   s!   € ÷ ñ  zð ¸Mð Èdñ r   c                	óÔ   € R Vn         VP                  '       g=   VP                  '       g)    \        P                  ! V P                  W4      4       R # R # R #   \         d     R # i ; ir6   )rO   rG   rI   rz   Úensure_futureÚ_keepalive_sendrÚ   rÀ   s   &&&r   rÙ   Ú#WeComStreamMixin._on_keepalive_fireÎ   sT   € Ø $ˆÔØ——� $§,§, ,ðÜ×%Ò% d×&:Ñ&:¸4Ó&IÖJñ #/‘øô  ô Úðús   ­%A ÁA'Á&A'c               ó$   € V ^8„  d   QhRRRRRR/# r»   r   )r   s   "r   r   rj   Ö   s"   € ÷ 3ñ 3¨*ð 3¸}ð 3ÐQUñ 3r   c              ƒ  óœ  "  € VP                   '       g(   VP                  '       g   VP                  \        8¼  d   R# VP                  ;'       g    RpVP                  4       '       g   V P                  WR7       R#  V P                  VP                  VP                  VRR7      G Rj  x€L
  Y1n        T P                  YR7       R#  L  \         d    T P                  Y4        R# \         dU   p\        P                  RT P                  TP                   TP                  T4       T P                  YR7        Rp?R# Rp?ii ; i5i)z¦Re-send accumulated text as finish=false to refresh the window, then re-arm. Never a placeholder
(empty text skips); on 846604/846608 the turn is retired for Layer 2.Nr
   ©r¼   F©r^   z2[%s] keep-alive send failed (chat=%s, turn=%s): %s)rG   rI   rN   ÚMAX_INTERMEDIATE_FRAMESrF   r±   rÛ   Ú_send_stream_replyr3   rE   r	   rÇ   rƒ   r}   r~   r   r=   rM   )r   rµ   r¼   rm   Úexcs   &&&  r   rà   Ú WeComStreamMixin._keepalive_sendÖ   s	  é € ð �>�>ˆ>˜TŸ\Ÿ\˜\¨T×-KÑ-KÔOfÔ-fÙØ×'Ñ'×-Ð-¨2ˆØ�}‰}�ŠØ×Ñ ÐÔ6Ùð	Ø×)Ñ)¨$¯+©+°t·~±~ÀwÐW\Ð)Ó]×]Ð]ð ")ÔØ×Ñ˜DÐÖ2ñ ^øÜ&ô 	Ø×Ñ˜dÔ,ÚÜô 	Ü�L‰LÐMÈtÏyÉyÐZ^×ZfÑZfÐhl×hvÑhvÐx{Ô|Ø×Ñ ÐÔ6Ýûð	üse   ‚$E§)EÁEÁ*EÁ?,C Â+C
Â,C Â0EÃ
C ÃE	Ã(EÃ+E	Ã4E	Ã5A	EÄ>EÅE	Å	Ec               ó$   € V ^8„  d   QhRRRRRR/# )r   rm   r   Úlimitr   rR   r   )r   s   "r   r   rj   ì   s&   € ÷ fñ f¨#ð f°cð f¸cñ fr   c                ót   € V P                  R4      p\        V4      V8:  d   V # VRV P                  RRR7      # )zOTruncate to ``limit`` UTF-8 bytes (WeCom caps frames by bytes, not codepoints).zutf-8NÚignore)Úerrors)Úencoder€   Údecode)rm   rë   Úencodeds   && r   Ú_truncate_stream_contentÚ)WeComStreamMixin._truncate_stream_contentë   s?   € ð —.‘. Ó)ˆÜ˜g›,¨%Ô/ˆwÐe°W¸V¸e°_×5KÑ5KÈGÐ\dÐ5KÓ5eÐer   c          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r   ri   r   rE   rm   r^   r+   rR   r(   r   )r   s   "r   r   rj   ñ   s2   € ÷ ñ °Sð ÀSð ÐSVð Ð`dð Ðqñ r   c           	   ƒ  ó¶  "  € T P                  T;'       g    RV P                  4      p\        T;'       g    R4      \        V4      8w  d"   \        P	                  RV P
                  V4       RRRRVR\        V4      RV//pV'       g   V P                  WRR	R
7      G Rj  x€L
 # V P                  WR	RR
7      G Rj  x€L
 pVP                  R^ 4      pV\        \        39   d0   \        T\        VP                  R4      ;'       g    R4      R7      hV\        8X  d#   \        P                  RV P
                  4       V# V P                  VR4       V#  L³ L™5i)z·Send one ``msgtype: "stream"`` frame: intermediates non-blocking/skip-if-pending, the final frame awaits
its ack so 846608/6000 are detected. Raises WeComStreamExpiredError on expiry.r
   z.[%s] Stream content truncated for stream_id=%sÚmsgtyperT   r\   r^   rm   FT)r,   rg   Nr   r   r   uv   [%s] finalize hit errcode 6000 (version conflict) â€” bubble already replaced by a newer frame; treating as delivered.zsend stream reply)rò   ÚMAX_STREAM_CONTENT_LENGTHr€   r}   rŠ   r   r+   rŽ   rV   r#   ÚSTREAM_REQUEST_EXPIRED_ERRCODEr	   r   ÚSTREAM_VERSION_CONFLICT_ERRCODEÚinfoÚ_raise_for_wecom_error)	r   ri   rE   rm   r^   Ú	truncatedr)   Úresponser   s	   &&&&&    r   rç   Ú#WeComStreamMixin._send_stream_replyñ   sJ  é € ð ×1Ñ1°'·-°-¸RÀ×A_ÑA_Ó`ˆ	Üˆw�}ˆ}˜"Ó¤ Y£Ô/Ü�N‰NÐKÈTÏYÉYÐXaÔbØ )¨8°XÀÀiÐQYÔ[_Ð`fÓ[gÐirÐt}Ð?~ÐˆßØ×0Ñ0°ÈeÐeiÐ0Ój×jÐjØ×0Ñ0°ÈdÐdiÐ0Ój×jˆØ—,‘,˜y¨!Ó,ˆØÔ-Ô/MÐNÔNÜ)°'Ä#ÀhÇlÁlÐS[ÓF\×FbÐFbÐ`bÓBcÔdÐdØÔ5Ô5ä�K‰Kð  Qð  SW÷  S\ñ  S\ô  ]ØˆOØ×#Ñ# HÐ.AÔBØˆñ kÙjùs1   ‚4E·A*EÂ!EÂ"EÂ=EÂ>A	EÄAEÅEÚfinalizer=   Nr¬   c          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r   Útextr   rÿ   r+   r=   r­   r¬   rR   r   )r   s   "r   r   rj     sA   € ÷ jñ j¨Cð j¸dð jÐUbð jð  vCð jð  Y]ñ jr   c             ‹  óz  a aaaaa"  € T;'       g    RP                  4       oS'       g#   \        P                  RS P                  4       R# VP	                  R4      oS'       g   SS P
                  9   d   R# VVVV VV3R lpS'       d   S P                  SVRR7      G Rj  x€L
 # V! 4       G Rj  x€L
 #  L L5i)	uá   Gateway streaming entry point: first call seeds the turn, later calls push cumulative text, ``finalize=True``
closes it; ``turn_id`` kwarg keys concurrent turns. Returns False when unavailable â€” caller falls back to send().r
   z([%s] send_stream_frame: chat_id requiredFr¼   c                 ó0   <€ SP                  SS SSSR 7      # ))Úchatr¬   rÿ   r¼   )Ú_send_stream_frame_inner)r  rÿ   r¬   r   r  r¼   s   €€€€€€r   Ú<lambda>Ú4WeComStreamMixin.send_stream_frame.<locals>.<lambda>  s   ø€ ˜×5Ñ5°dÀÐPXÐckÐu|Ð5Ô}r   T)Ú
is_controlN)r±   r}   rŠ   r   rV   rÅ   Ú_enqueue_chat_send)	r   r  rÿ   r=   r¬   ÚkwargsÚinnerr  r¼   s	   ffd$d, @@r   Úsend_stream_frameÚ"WeComStreamMixin.send_stream_frame  s�   ýé € ð —�˜2×$Ñ$Ó&ˆßÜ�N‰NÐEÀtÇyÁyÔQÙØ—*‘*˜YÓ'ˆç˜4 4×#=Ñ#=Ô=Ùß}Ñ}ˆçNV�T×,Ñ,¨T°5ÀTÐ,ÓJ×JÐiÑbgÓbi×\iÐiÑJÑ\iùs4   ˆ"B;«:B;Á&%B;ÂB;Â#B7Â$B;Â2B9Â3B;Â9B;c          
     ó,   € V ^8„  d   QhRRRRRRRRRR	/# )
r   r  r   r¬   r­   rÿ   r+   r¼   rR   rÊ   r   )r   s   "r   r   rj     s1   € ÷ ñ  ð °ð Èð ÐXeð Ðj~ñ r   c           	     óp  € V'       dW   V P                   P                  V RV 24      pV'       d   V# V'       d$   \        P                  RV P                  WA4       R# MGV P                  V4      ;p'       d/   \        P                  RV P                  VP                  V4       V# V'       d   RV R2MRpWP                  9   d   RMV P                  W4      pV'       g?   WP                  9   d   RMR	p	\        P                  R
V	,           V P                  W4       R# T RT;'       g    T 2p
V'       d   RMV P                   P                  V
4      ;'       g    \        W4      pWPP                   V
&   \        P                  RV P                  VP                  V'       d	   RV RV 2MRV 2V4       V# )zXFind or create the StreamTurn (None = unavailable); a turn locks to its creation req_id.r¾   zO[%s] send_stream_frame: cannot finalize non-existent turn (turn_id=%s, chat=%s)Nz<[%s] send_stream_frame: reusing existing turn %s for chat %sz
 (turn_id=Ú)r
   z,chat %s is expired, cannot create new turn%sz!no req_id available for chat %s%sz[%s] send_stream_frame: z<[%s] send_stream_frame: created new turn %s (%s) for chat %szturn_id=z	, req_id=zreq_id=)
r¿   rV   r}   r~   r   rÒ   rE   rÅ   r²   r;   )r   r  r¬   rÿ   r¼   rµ   Úexisting_turnÚsuffixr3   ÚwhyÚkeys   &&&&&      r   Ú_locate_turnÚWeComStreamMixin._locate_turn  sÕ  € çØ×%Ñ%×)Ñ)¨T¨F°!°G°9Ð*=Ó>ˆDßØ�ßÜ—‘ÐnÐpt×pyÑpyð  |Cô  JÙð ð #×=Ñ=¸dÓCÐCˆ]ÖCÜ�L‰LÐWÐY]×YbÑYbÐdq×d{Ñd{ð  ~Bô  CØ Ð ß,3�:˜g˜Y aÑ(¸ˆØ×!;Ñ!;Ô;‘À×A\ÑA\Ð]aÓAlˆßØDH×LfÑLfÔDfÑ@ð  mPˆCÜ�L‰LÐ3°cÕ9¸4¿9¹9ÀdÔSÙØ��a˜×)Ð) 6Ð*Ð+ˆß‘ T×%7Ñ%7×%;Ñ%;¸CÓ%@×]Ð]ÄZÐPTÓE]ˆØ"&×Ñ˜3ÑÜ�‰ÐSÐUY×U^ÑU^Ð`d×`nÑ`n÷  ZaÐrzð  |Cð  {Dð  DMð  NTð  MUñ  qVð  ipð  qwð  pxð  gyð  {ô  	@Øˆr   c          
     ó,   € V ^8„  d   QhRRRRRRRRRR	/# )
r   rµ   r;   r  r   r  r¼   r­   rR   r+   r   )r   s   "r   r   rj   ,  s1   € ÷ ñ ¨ð ¸3ð Àcð ÐTað Ðfjñ r   c              ƒ  ób  "  € V P                   '       gv   \        P                  ! 4       VP                  ,
          pWPP                  8¼  d@   \
        P                  RV P                  WPP                  V4       V P                  W4       R# V P                  V4       V'       d   W!P                  8X  d
   VR,           MTpV P                  VP                  VP                  VRR7      G Rj  x€L
  RVn        V P                  P!                  T RT;'       g    VP                   2R4       R#  LB5i)zGSend the finish=true frame (or decline via the Layer 2 clock fallback).u�   [%s] Stream age %.0fs >= safe duration %.0fs for chat %s â€” declining finalize frame, falling back to proactive send (Layer 2 clock fallback).Fu   â€‹Trå   Nr¾   )rÖ   rJ   rK   rL   Ú_stream_safe_duration_secondsr}   rú   r   rÇ   r¸   rM   rç   r3   rE   rG   r¿   r™   )r   rµ   r  r  r¼   Ú
stream_ageÚ
final_texts   &&&&&  r   Ú_finalize_turnÚWeComStreamMixin._finalize_turn,  sõ   é € ð ×-×-Ð-ÜŸšÓ)¨D¯O©OÕ;ˆJØ×?Ñ?Ô?Ü—‘ð fØ—I‘I˜z×+MÑ+MÈtôð ×!Ñ! $Ô0ÙØ×Ñ˜tÔ$ç(,°×9OÑ9OÔ1O�T˜H–_ÐUYˆ
Ø×%Ñ% d§k¡k°4·>±>À:ÐVZÐ%Ó[×[Ð[ØˆŒØ×Ñ×Ñ $  q¨×)?Ð)?°D·K±KÐ(@ÐAÀ4ÔHÙñ 	\ùs   ‚B D/Â#AD/Ã*D-Ã++D/ÄD/r¼   c               ó0   € V ^8„  d   QhRRRRRRRRRRR	R/# )
r   r  r   r  r¬   r­   rÿ   r+   r¼   rR   r   )r   s   "r   r   rj   A  sB   € ÷ (ñ (°3ð (Àð (ÐP]ð (Ðptð (ð  HUð (ð  aeñ (r   c             ƒ  	óÜ  "  € R p V P                  W#WE4      pVe   VP                  '       d   R# VP                  '       go   VP                  '       g]   V P	                  VP
                  VP                  RRR7      G R j  x€L
  RVn        V P                  WeR7       V'       g   V'       g   R# V'       d   V P                  WaW%4      G R j  x€L
 # Wn	        VP                  \        8¼  g   WP                  8X  d   R# V P	                  VP
                  VP                  VRR7      G R j  x€L
  V;P                  ^,          un
        Wn        R#  LÐ L… L)  \         d�    T'       g*   \        P                  RT P                   \"        T4        R# \        P                  RT P                   \"        T4       Tf   T P$                  P'                  T4        R# T P)                  Ye4        R# \*         dq   pT'       g(   \        P                  RT P                   Y'4        R p?R# \        P-                  R	T P                   Y'4       Te   T P/                  Ye4        R p?R# R p?ii ; i5i)
NFz<think></think>rå   Trä   ue   [%s] Intermediate stream frame expired (errcode=%d) for chat %s â€” dropping frame, stream stays liveuL   [%s] Stream expired (errcode=%d) for chat %s â€” switching to proactive senduY   [%s] Intermediate stream frame failed (chat=%s): %s â€” dropping frame, stream stays livez&[%s] Stream frame failed (chat=%s): %s)r  rI   rH   rG   rç   r3   rE   rÛ   r  rF   rN   ræ   rM   r	   r}   rú   r   r#   rÅ   rÆ   rÇ   rƒ   rŠ   rÁ   )r   r  r  r¬   rÿ   r¼   rµ   rè   s   &&$$$$  r   r  Ú)WeComStreamMixin._send_stream_frame_innerA  s$  é € Ø%)ˆð%	1Ø×$Ñ$ T°XÓGˆDØŠ|˜tŸ|Ÿ|˜|ÙØ—;—;�; t§~§~ ~à×-Ñ-¨d¯k©k¸4¿>¹>ÐK\ÐejÐ-Ók×kÐkØ"�”Ø×#Ñ# DÐ#Ô:ß§HÙßØ!×0Ñ0°¸TÓK×KÐKà$(Ô!Ø×-Ñ-Ô1HÔHÈD×TjÑTjÔLjÙØ×)Ñ)¨$¯+©+°t·~±~ÀtÐTYÐ)ÓZ×ZÐZØ×*Ò*¨aÕ/Õ*Ø%)Ô"Ùñ lñ Lñ
 [øô 'ô 		1çÜ—‘ð  Dð  FJ÷  FOñ  FOô  Qgð  imô  nÚÜ�K‰KÐfÐhl×hqÑhqô  tJð  LPô  QØŠ|Ø×*Ñ*×.Ñ.¨tÕ4ñ ð ×!Ñ! $Õ0ñ ô ô 	1ßÜ—‘ÐwÐy}÷  zCñ  zCð  EIô  OÝÜ�N‰NÐCÀTÇYÁYÐPTÔZØÒØ×!Ñ! $Ô0ûÙûð	1üsá   ‚I,†'E ®I,°E ÁE Á,E Â EÂ,E Â.I,Â0E Â8E ÃEÃE ÃI,Ã+E Ã=I,Ã?,E Ä+EÄ,#E ÅI,ÅE ÅE ÅE ÅI)Å*&I)ÆI,ÆAI)ÇI,ÇI)Ç,I,Ç/I)Ç8I)Ç9)I$È"I,È(6I$ÉI,É$I)É)I,c               ó$   € V ^8„  d   QhRRRRRR/# )r   Ú	chat_typer­   ÚmetadatazOptional[dict[str, Any]]rR   r+   r   )r   s   "r   r   rj   k  s#   € ÷ ñ °=ð ÐSkð Ðw{ñ r   c                ó
   € ??R# )zVStream frames work in DMs and groups alike (groups just need a cached inbound req_id).Tr   )r   r"  r#  s   &&&r   Úsupports_native_streamingÚ*WeComStreamMixin.supports_native_streamingk  s
   € à�xÙr   c               ó    € V ^8„  d   QhRRRR/# )r   r=   r   rR   r‘   r   )r   s   "r   r   rj   p  s   € ÷ ñ ¨ð Àñ r   c              ƒ  ó   "  € ??R# 5i)zhNo-op: the stream consumer's seed frame triggers WeCom typing; repeated calls would open orphan streams.Nr   )r   r=   r#  s   &&&r   Úsend_typingÚWeComStreamMixin.send_typingp  s
   é € à’Xùs   ‚r   )F)NNr6   )r   r   r    r!   r"   r÷   rˆ   rŽ   ry   r„   r    r©   r²   Ústaticmethodr¸   rÁ   rÇ   rÒ   rÛ   rÙ   rà   rò   rç   r  r  r  r  r%  r)  r$   r   r   r   rf   rf   U   só   † Ùpà 9ÐØÐð$<Ðdið $<ð  DI÷ $<õL!õ 1õõ#õ{ð ôó ðõQõ
5õ
põõõ3ð* ôfó ðf÷
ð(jÀUð jÐeið jð  FJ÷ jõõ0ð*(Ð`dð (Ðw|ð (ð  X\÷ (÷T÷
ó r   rf   )"r"   Ú
__future__r   rz   ÚloggingrJ   rB   Údataclassesr   Útypingr   r   r   Ú	getLoggerr}   r‚   r#   rø   ÚSTREAM_NOT_SUBSCRIBED_ERRCODErù   r÷   ræ   ÚSTREAM_SAFE_DURATION_SECONDSÚ!STREAM_KEEPALIVE_INTERVAL_SECONDSÚ STREAM_KEEPALIVE_ENABLED_DEFAULTrÚ   r	   r'   r1   r;   rX   r_   rd   rf   r   r   r   Ú<module>r5     sÎ   ðñlõ #ã Û Û Û Ý !ß &Ñ &à	×	Ò	Ð<Ó	=€à&Ð ð
  Ð Ø!'Ð Ø &Ð Ø"&Ð Ø!Ð àÐ ð  %Ð Ø$)Ð !Ø#(Ð  ô4˜lô 4ð ÷$ð $ó ð$÷5ñ 5÷	Dñ 	DõRõ@õ
:÷]ó ]r   