+
    kHàj†  ã                  ór   € R t ^ RIHt ^ RIt^ RIt^ RIt^ RIHt ]P                  ! R4      t	 ! R R4      t
R# )zâPer-chat FIFO send queues (OpenClaw chat-queue.ts) + token bucket for WeCom's 30 msgs/min/chat limit (846607).
Two lanes per chat: normal, and a control lane (approval prompts, finalize frames) backed by a reserved token pool.)ÚannotationsN)ÚDictzplugins.platforms.wecom.adapterc                  ój   € ] tR t^tRt^t^t^tR R ltRR R llt	R R lt
RR R	 lltR
 R ltRtR# )ÚChatSendQueueMixinz`Expects ``_chat_queues/_chat_workers/_control_queues/_control_workers/_chat_token_usage`` dicts.c               ó    € V ^8„  d   QhRRRR/# )é   Úchat_idÚstrÚreturnzdict[str, float]© )Úformats   "ÚG/home/ubuntu/.hermes/hermes-agent/plugins/platforms/wecom/send_queue.pyÚ__annotate__ÚChatSendQueueMixin.__annotate__   s   € ÷ Oñ O¨ð OÐ0@ñ Oó    c           
     	ó®   € V P                   P                  \        T;'       g    R 4      P                  4       RRRRR\        P
                  ! 4       /4      # )Ú Únormalç        ÚreservedÚ
last_reset)Ú_chat_token_usageÚ
setdefaultr	   ÚstripÚtimeÚ	monotonic)Úselfr   s   &&r   Ú_get_token_usageÚ#ChatSendQueueMixin._get_token_usage   sd   € Ø×%Ñ%×0Ñ0´°W·]°]ÀÓ1C×1IÑ1IÓ1KÈhÐX[Ð]gÐilÐnzô  }A÷  }Kò  }Kó  }Mð  NNó  Oð  	Or   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r   r	   Ú
is_controlÚboolr
   Úfloatr   )r   s   "r   r   r      s!   € ÷ 
2ñ 
2¨3ð 
2¸Dð 
2ÈUñ 
2r   c                óv  € V P                  V4      p\        P                  ! 4       pWCR,          ,
          R8”  d   VP                  RRVR7       RV P                  R3RV P
                  V33 F4  w  rVpV'       g   K  W5,          V8  g   K  W5;;,          R,          uu&    R# 	  RWCR,          ,
          ,
          # )	z’Consume one token: 0 if available, else seconds until the next minute window. Control messages use the normal quota first, then the reserved pool.r   g      N@r   )r   r   r   r   Tr   g      ð?)r   r   r   ÚupdateÚ_BUCKET_NORMAL_TOKENSÚ_BUCKET_RESERVED_TOKENS)r   r   r    ÚusageÚnowÚlaneÚcapÚalloweds   &&&     r   Ú_bucket_try_consumeÚ&ChatSendQueueMixin._bucket_try_consume   s¯   € à×%Ñ% gÓ.ˆÜ�nŠnÓˆØ�|Õ$Õ$ tÔ+Ø�L‰L ¨c¸cˆLÔBØ$,¨d×.HÑ.HÈ$Ð#OÐR\Ð^b×^zÑ^zð  }Gð  RHó  #IÑˆD�wß‰w˜5�;¨Ö,Ø—˜sÕ"“Úñ #Ið �s <Õ0Õ0Õ1Ð1r   c               ó   € V ^8„  d   QhRR/# )r   r    r!   r   )r   s   "r   r   r   %   s   € ÷ xñ x ñ xr   c                	ór   € V'       d   V P                   V P                  3# V P                  V P                  3# )N)Ú_control_queuesÚ_control_workersÚ_chat_queuesÚ_chat_workers)r   r    s   &&r   Ú_laneÚChatSendQueueMixin._lane%   s3   € ß@J�×$Ñ$ d×&;Ñ&;Ð<ÐwÐQU×QbÑQbÐdh×dvÑdvÐPwÐwr   c               ó    € V ^8„  d   QhRRRR/# )r   r   r	   r    r!   r   )r   s   "r   r   r   (   s   € ÷ ñ °ð Ètñ r   c              ƒ  ó^  "  € \        T;'       g    R4      P                  4       pV'       d   RMRpV P                  V4      w  rgWF9  d`   \        P	                  RV P
                  WT4       \        P                  ! 4       Wd&   \        P                  ! V P                  WC4      4      Wt&   Wd,          p\        P	                  RV P
                  WEVP                  4       4       \        P                  ! 4       P                  4       p	VP                  W)34      G Rj  x€L
  V	G Rj  x€L
 #  L L5i)z‘Enqueue a send for a chat and await its result (FIFO per chat); the control lane bypasses the normal queue so approval prompts are never blocked.r   Úcontrolr   z+[%s] Creating %s queue + worker for chat %sz3[%s] Enqueuing send for chat %s (lane=%s, qsize=%d)N)r	   r   r4   ÚloggerÚdebugÚnameÚasyncioÚQueueÚcreate_taskÚ_send_workerÚqsizeÚget_running_loopÚcreate_futureÚput)
r   r   Úcoro_factoryr    Úkeyr)   ÚqueuesÚworkersÚqueueÚfutures
   &&&&      r   Ú_enqueue_chat_sendÚ%ChatSendQueueMixin._enqueue_chat_send(   sâ   é € ä�'—-�-˜RÓ ×&Ñ&Ó(ˆß&‰y¨HˆØŸ*™* ZÓ0‰ˆØÔÜ�L‰LÐFÈÏ	É	ÐSWÔ]Ü!Ÿ-š-›/ˆF‰KÜ"×.Ò.¨t×/@Ñ/@ÀÓ/QÓRˆG‰LØ•ˆÜ�‰ÐJÈDÏIÉIÐWZÐbg×bmÑbmÓboÔpÜ×)Ò)Ó+×9Ñ9Ó;ˆØ�i‰i˜Ð.Ó/×/Ð/Ø�|Ðñ 	0Ùùs)   ‚+D-®C,D-ÄD)Ä	D-Ä$D+Ä%D-Ä+D-c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úchat_keyr	   r    r!   r
   ÚNoner   )r   s   "r   r   r   7   s&   € ÷ Vñ V¨3ð V¸Dð VÀTñ Vr   c              ƒ  óè  "  € V P                  V4      ^ ,          V,          pV'       g"   \        P                  RV P                  V4         VP	                  4       G Rj  x€L
 w  rE V P                  W4      pV^ 8”  dY   V'       g"   \        P                  RV P                  W4       \        P                  ! V4      G Rj  x€L
  V P                  W4       V! 4       G Rj  x€L
 pVP                  4       '       g   VP                  V4       TP                  4        KÔ   L¿ L_ LA  \         d2   pTP                  4       '       g   TP                  T4        Rp?LORp?ii ; i  TP                  4        i ; i  \        P                   da    TP                  4       '       gG   TP                  4       w  r•TP                  4       '       d   K@  TP                  \!        R4      4       K\   R# i ; i5i)z?Per-chat worker: drain one lane's queue under the token bucket.z+[%s] Normal send worker started for chat %sNz:[%s] Normal worker rate-limited for chat %s, waiting %.1fszWeCom adapter shutting down)r4   r9   r:   r;   Úgetr,   r<   ÚsleepÚdoneÚ
set_resultÚ	ExceptionÚset_exceptionÚ	task_doneÚCancelledErrorÚemptyÚ
get_nowaitÚRuntimeError)
r   rM   r    rH   rD   rI   ÚwaitÚresultÚexcÚ_s
   &&&       r   r?   ÚChatSendQueueMixin._send_worker7   st  é € à—
‘
˜:Ó& qÕ)¨(Õ3ˆßÜ�L‰LÐFÈÏ	É	ÐS[Ô\ð	VØØ-2¯Y©Y«[×'8Ñ$�ð&Ø×3Ñ3°HÓI�DØ˜a”xß)Ü"ŸL™LÐ)eÐgk×gpÑgpÐrzô  BÜ%Ÿmšm¨DÓ1×1Ð1Ø×0Ñ0°ÔFÙ#/£>×1�FØ!Ÿ;™;Ÿ=š=Ø×)Ñ)¨&Ô1ð
 —O‘OÖ%ñ (9ñ 2á1øô !ô 2Ø!Ÿ;™;Ÿ=š=Ø×,Ñ,¨SÔ1ÿøð2ûð —O‘OÕ%ûÜ×%Ñ%ô 	VØ—k‘k—m’mØ!×,Ñ,Ó.‘	�Ø—{‘{—}”}Ø×(Ñ(¬Ð6SÓ)TÖUò $ð	Vüs¢   ‚A	G2ÁE: Á D Á!E: Á(D& Â:D& ÃD"ÃD& Ã"D$Ã#D& Ã=D& ÄE: Ä"D& Ä$D& Ä&E"Ä1'EÅE% ÅE"Å"E% Å%E7Å7E: Å:*G/Æ%%G/ÇG/Ç+G2Ç.G/Ç/G2r   N)F)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú_BUCKET_MAX_TOKENSr%   r&   r   r,   r4   rJ   r?   Ú__static_attributes__r   r   r   r   r      s;   † Ùjð ÐØÐØÐõO÷
2õx÷÷Vñ Vr   r   )rd   Ú
__future__r   r<   Úloggingr   Útypingr   Ú	getLoggerr9   r   r   r   r   Ú<module>rk      s;   ðñwõ #ã Û Û Ý à	×	Ò	Ð<Ó	=€÷DVó DVr   