+
    jHàj²  ã                  ór   € R t ^ RIHt ^ RIt^ RIHtHt ^ RIHt ]P                  ! R4      t
 ! R R4      tR# )ay  Think-block filtering for GatewayStreamConsumer.

Some models emit inline <think>...</think> blocks in content.  The agent strips
them from the final response, but intermediate edits go out before that, so this
mirrors the CLI's _stream_delta state machine; tag primitives are shared with
``agent/think_scrubber.py`` so the progressive display matches the post-stream scrubber.)ÚannotationsN)ÚTHINK_CLOSE_TAGSÚTHINK_OPEN_TAGS)ÚStreamingThinkScrubberzgateway.stream_consumerc                  óh   € ] tR t^tRt]t]tR R lt	R R lt
R R lt]R R	 l4       tR
 R ltRtR# )ÚStreamThinkFilterMixinz9Progressive <think>-tag suppression over streamed deltas.c               ó$   € V ^8„  d   QhRRRRRR/# )é   ÚbufÚstrÚidxÚintÚreturnÚbool© )Úformats   "ÚB/home/ubuntu/.hermes/hermes-agent/gateway/stream_consumer_think.pyÚ__annotate__Ú#StreamThinkFilterMixin.__annotate__   s!   € ÷ 5ñ 5 cð 5°ð 5¸ñ 5ó    c                ó(  € V P                   '       * ;'       g    V P                   P                  R4      pV^ 8X  d   V# VRV pVP                  R4      pVR8X  d   T;'       d    VP                  4       R8H  # WE^,           R P                  4       R8H  # )z†Tag at ``idx`` starts a block: start of text, or newline + optional whitespace.

Prose that merely *mentions* a tag must not trigger.
Ú
NÚ éÿÿÿÿ)Ú_accumulatedÚendswithÚrfindÚstrip)Úselfr
   r   Úacc_boundaryÚ	precedingÚlast_nls   &&&   r   Ú_at_block_boundaryÚ)StreamThinkFilterMixin._at_block_boundary   s�   € ð
  ×,Ñ,Ô,×PÐP°×0AÑ0A×0JÑ0JÈ4Ó0PˆØ�!Œ8ØÐØ˜˜�Iˆ	Ø—/‘/ $Ó'ˆØ�bŒ=Ø×;Ð; I§O¡OÓ$5¸Ñ$;Ð;Ø 1�˜Ð&×,Ñ,Ó.°"Ñ4Ð4r   c               ó$   € V ^8„  d   QhRRRRRR/# )r	   r
   r   Ú	lower_bufr   ztuple[int, int]r   )r   s   "r   r   r   &   s!   € ÷ "ñ " cð "°cð "¸oñ "r   c                ó  € R^ rCV P                    Fj  pVP                  4       p^ pVP                  Wg4      ;pR8w  g   K/  V P                  W4      '       d   VR8X  g   Wƒ8  d   T\	        V4      rCKa  V^,           pKW  	  W43# )zG(index, length) of the earliest block-boundary opening tag, or (-1, 0).r   )Ú_OPEN_THINK_TAGSÚlowerÚfindr"   Úlen)	r   r
   r%   Úbest_idxÚbest_lenÚtagÚ	tag_lowerÚsearch_startr   s	   &&&      r   Ú_earliest_open_tagÚ)StreamThinkFilterMixin._earliest_open_tag&   s}   € à �(Ø×(Ô(ˆCØŸ	™	›ˆIØˆLØ#Ÿ.™.¨ÓAÐA�3ÀbÖHØ×*Ñ*¨3×4Ò4Ø 2”~¨¬Ø-0´#°c³( (ÙØ" Q�w’ñ )ð Ð!Ð!r   c               ó    € V ^8„  d   QhRRRR/# )r	   Útextr   r   ÚNoner   )r   s   "r   r   r   4   s   € ÷ &ñ &¨3ð &°4ñ &r   c                óÜ  € V P                   V,           pRV n         V'       EdI   VP                  4       pV P                  '       dy   \        P                  ! W P
                  4      w  rEV'       d   RV n        W$V,           R pKi  \        R V P
                   4       4      p\        V4      V8”  d   W&) R MTV n         R# V P                  W#4      w  rEV'       d)   V P                  VRV 4       RV n        W$V,           R pKæ  \        P                  ! W P                  4      pV'       d"   V P                  VRV)  4       W') R V n         R# V P                  V P                  V4      4       R# R# )z¢Append a delta to the buffer, discarding think blocks.

Partial tags at buffer boundaries are held in ``_think_buffer`` until
enough characters arrive to decide.
r   FNc              3  ó8   "  € T F  p\        V4      x € K  	  R # 5i)N)r*   )Ú.0Úts   & r   Ú	<genexpr>Ú@StreamThinkFilterMixin._filter_and_accumulate.<locals>.<genexpr>G   s   é € Ð!IÑ2H¨Q¤# a§& &Ó2Hùs   ‚T)Ú_think_bufferr(   Ú_in_think_blockÚ	_ScrubberÚ_find_first_tagÚ_CLOSE_THINK_TAGSÚmaxr*   r0   Ú_append_accumulatedÚ_max_partial_suffixr'   Ú_strip_orphan_close_tags)r   r3   r
   r%   r+   r,   Úmax_tagÚ	held_backs   &&      r   Ú_filter_and_accumulateÚ-StreamThinkFilterMixin._filter_and_accumulate4   sN  € ð × Ñ  4Õ'ˆØˆÔçˆcàŸ	™	›ˆIØ×#×#Ð#Ü%.×%>Ò%>¸s×DZÑDZÓ%[Ñ"�ßØ+0�DÔ(Ø¨Õ1Ð2Ð3’Cô "Ñ!I°$×2HÒ2HÓ!IÓI�GÜ;>¸s»8ÀgÔ;M¨¨X¨Y©ÐSV�DÔ&Ùà%)×%<Ñ%<¸SÓ%LÑ"�ßØ×,Ñ,¨S°°(¨^Ô<Ø+/�DÔ(Ø¨Õ1Ð2Ð3’Cô !*× =Ò =¸c×CXÑCXÓ Y�Iß Ø×0Ñ0°°[°y°jÐ1AÔBØ-0°°Ð-=˜Ô*ñ
 ð ×0Ñ0°×1NÑ1NÈsÓ1SÔTÙñ; r   c               ó    € V ^8„  d   QhRRRR/# )r	   r3   r   r   r   )r   s   "r   r   r   ]   s   € ÷ 8ñ 8 sð 8¨sñ 8r   c                ó.   € \         P                  ! V 4      # )zHRemove close tags (plus trailing whitespace) that have no matching open.)r=   rC   )r3   s   &r   rC   Ú/StreamThinkFilterMixin._strip_orphan_close_tags\   s   € ô ×1Ò1°$Ó7Ð7r   c               ó   € V ^8„  d   QhRR/# )r	   r   r4   r   )r   s   "r   r   r   a   s   € ÷ $ñ $ Tñ $r   c                ó¸   € V P                   '       dH   V P                  '       g4   V P                  V P                  V P                   4      4       RV n         R# R# R# )zDOn stream end, flush text held back waiting for a possible open tag.r   N)r;   r<   rA   rC   )r   s   &r   Ú_flush_think_bufferÚ*StreamThinkFilterMixin._flush_think_buffera   sH   € à××Ð d×&:×&:Ð&:Ø×$Ñ$ T×%BÑ%BÀ4×CUÑCUÓ%VÔWØ!#ˆDÖñ ';Ñr   )r<   r;   N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r   r'   r   r?   r"   r0   rF   ÚstaticmethodrC   rM   Ú__static_attributes__r   r   r   r   r      s?   † ÙCà&ÐØ(Ðõ5õ"õ&ðP ô8ó ð8÷$ñ $r   r   )rS   Ú
__future__r   ÚloggingÚagent.think_scrubberr   r   r   r=   Ú	getLoggerÚloggerr   r   r   r   Ú<module>r[      s6   ðñ\õ #ã ç BÝ Dà	×	Ò	Ð4Ó	5€÷S$ó S$r   