
    sj                        U d Z ddlmZ ddlZddlZddlZddlZddlmZm	Z	 dgZ
 ej                    Zi Zded<   i Zded	<   i Zd
ed<    G d d          Z G d d          ZddZej        dd            ZdS )u!  Thread-scoped stdout/stderr silencing for background worker threads.

``contextlib.redirect_stdout``/``redirect_stderr`` reassign the *process-global*
``sys.stdout``/``sys.stderr``.  When a daemon worker thread (e.g. the background
memory/skill review) wraps its whole body in those context managers, every other
thread in the process — including a gateway's asyncio event-loop thread driving a
Telegram long-poll — sees ``sys.stdout``/``sys.stderr`` pointing at ``devnull``
for the full duration.  Any bare ``print`` / ``sys.stderr.write`` from those other
threads is silently lost during that window (see issue #55769 / #55925).

This module installs a thin proxy as ``sys.stdout``/``sys.stderr`` that routes
writes per-thread: threads registered as "silenced" go to a sink; every other
thread passes through to the *original* stream.  The proxy is installed once,
idempotently, and is never uninstalled (uninstalling would race other threads
mid-write), so the only observable effect for unregistered threads is one extra
attribute lookup per write.
    )annotationsN)IteratorTextIOthread_scoped_silencez!dict[str, '_ThreadRoutingStream']
_installedzdict[str, TextIO]_sinkszdict[str, '_RoutingState']_routing_statesc                      e Zd ZdZddZdS )	_RoutingStatezCSilencing registry shared by every proxy generation for one stream.sinkr   returnNonec                R    || _         i | _        t          j                    | _        d S N)r   silenced	threadingLocklock)selfr   s     >/home/agent/.hermes/hermes-agent/agent/thread_scoped_output.py__init__z_RoutingState.__init__+   s#    	(*N$$			    N)r   r   r   r   )__name__
__module____qualname____doc__r    r   r   r   r   (   s.        MM% % % % % %r   r   c                  X    e Zd ZdZddZdd	ZddZddZd Zd Z	d Z
ddZd Zd ZdS )_ThreadRoutingStreama  A ``sys.stdout``/``sys.stderr`` stand-in that routes writes per-thread.

    Threads whose ident is in ``_silenced`` write to ``_sink``; all other
    threads write to ``_passthrough`` (the original stream captured at install
    time).  Attribute access for anything other than the methods we override
    is delegated to the *current* target so things like ``.encoding`` /
    ``.fileno()`` behave like the underlying stream for the calling thread.
    passthroughr   stater   r   r   c                "    || _         || _        d S r   )_passthrough_state)r   r    r!   s      r   r   z_ThreadRoutingStream.__init__;   s    'r   c                    | j         j                            t          j                    d          dk    r| j         j        S | j        S Nr   )r$   r   getr   	get_identr   r#   r   s    r   _targetz_ThreadRoutingStream._target?   s?    ;##I$7$9$91==AA;##  r   identintc                    | j         j        5  | j         j                            |d          dz   | j         j        |<   d d d            d S # 1 swxY w Y   d S Nr      )r$   r   r   r'   )r   r+   s     r   silencez_ThreadRoutingStream.silenceE   s    [ 	Q 	Q*.+*>*B*B5!*L*Lq*PDK '	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Qs   1AAAc                   | j         j        5  | j         j                            |d          dz
  }|dk    r|| j         j        |<   n | j         j                            |d            d d d            d S # 1 swxY w Y   d S r.   )r$   r   r   r'   pop)r   r+   depths      r   	unsilencez_ThreadRoutingStream.unsilenceI   s    [ 	6 	6K(,,UA66:Eqyy.3$U++$((555	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6s   AA44A8;A8c                    	 |                                                      |          S # t          $ r) t          |t                    rt          |          ndcY S w xY wr&   )r*   write	Exception
isinstancestrlen)r   datas     r   r6   z_ThreadRoutingStream.writeR   sc    	=<<>>''--- 	= 	= 	= *4 5 5<3t9991<<<	=s   &) 0AAc                r    	 |                                                                  S # t          $ r Y d S w xY wr   )r*   flushr7   r)   s    r   r=   z_ThreadRoutingStream.flushX   sC    	<<>>''))) 	 	 	44	s   %( 
66c                x    |                                  }	 |                    |          S # t          $ r Y d S w xY wr   )r*   
writelinesr7   )r   linestargets      r   r?   z_ThreadRoutingStream.writelines^   sJ    	$$U+++ 	 	 	44	s   + 
99boolc                    	 t          |                                                                           S # t          $ r Y dS w xY w)NF)rB   r*   isattyr7   r)   s    r   rD   z_ThreadRoutingStream.isattye   sK    	--//000 	 	 	55	s   25 
AAc                N    |                                                                  S r   )r*   filenor)   s    r   rF   z_ThreadRoutingStream.filenok   s    ||~~$$&&&r   c                F    t          |                                 |          S r   )getattrr*   )r   names     r   __getattr__z _ThreadRoutingStream.__getattr__n   s     t||~~t,,,r   N)r    r   r!   r   r   r   )r   r   )r+   r,   r   r   )r   rB   )r   r   r   r   r   r*   r0   r4   r6   r=   r?   rD   rF   rJ   r   r   r   r   r   1   s            ! ! ! !Q Q Q Q6 6 6 6= = =       ' ' '- - - - -r   r   attrr9   r    r   r   '_ThreadRoutingStream'c                   t           5  t                              |           }t          t          | d          }t          |t                    r'|t          | <   |j        t          | <   |cddd           S |||u r|cddd           S ||n|}t                              |           }||j
        r&t          t          j        dd          }|t          | <   t                              |           }|	|j        |urt          |          }|t          | <   t          ||          }t!          t          | |           |t          | <   |cddd           S # 1 swxY w Y   dS )zGInstall (idempotently) a routing proxy as ``sys.<attr>`` and return it.Nwzutf-8)encoding)_install_lockr   r'   rH   sysr8   r   r$   r	   r   closedopenosdevnullr   r   setattr)rK   r    proxycurrentr   r!   s         r   _ensure_installedrY   t   s   	  t$$#tT**g344 	  'Jt$+NOD!        E!1!1        ")!4gg+zz$<4;<
C':::DF4L##D))=EJd22!$''E$)OD!$[%88T5!!! 
47                 s   A E5E	B>EEEIterator[None]c               #    K   t          j                    } t          dt          j        pt          j                  }t          dt          j        pt          j                  }|                    |            |                    |            	 dV  |	                    |            |	                    |            dS # |	                    |            |	                    |            w xY w)a-  Silence ``stdout``/``stderr`` for the *current thread only*.

    Other threads keep writing to the real streams.  Use this around a worker
    thread's body instead of ``contextlib.redirect_stdout(devnull)`` when the
    process is multi-threaded and another thread must keep its console output.
    stdoutstderrN)
r   r(   rY   rQ   
__stdout__r\   
__stderr__r]   r0   r4   )r+   	out_proxy	err_proxys      r   r   r      s       !!E!(CN,HcjIII!(CN,HcjIIIee#E"""E""""" 	E"""E""""s   B= =,C))rK   r9   r    r   r   rL   )r   rZ   )r   
__future__r   
contextlibrT   rQ   r   typingr   r   __all__r   rP   r   __annotations__r   r	   r   r   rY   contextmanagerr   r   r   r   <module>rh      sT    $ # " " " " "     				 



     # # # # # # # #"
#	   13
 2 2 2 2     .0 0 0 0 0% % % % % % % %@- @- @- @- @- @- @- @-F   @ # # # # # #r   