
    JjI                        d Z ddlmZ ddlZddlZddlZddlmZm	Z	 ddl
mZmZ daddZ G d	 d
          Z G d d          Zd dZd!dZ	 d"dddd#dZd$dZ e            Zg dZdS )%u  Process-level bootstrap helpers for ``run_agent``.

Three concerns, all tied to ``AIAgent`` boot-time / runtime IO setup:

1. **Lazy OpenAI SDK import** — ``_load_openai_cls`` + ``_OpenAIProxy``
   defer the 240ms-ish ``from openai import OpenAI`` cost until first use,
   while preserving ``isinstance(client, OpenAI)`` checks and
   ``patch("run_agent.OpenAI", ...)`` test patterns.

2. **Crash-resistant stdio** — ``_SafeWriter`` wraps stdout/stderr so
   ``OSError: Input/output error`` from broken pipes (systemd, Docker,
   thread teardown races) cannot crash the agent.  ``_install_safe_stdio``
   applies the wrapper.

3. **HTTP proxy resolution** — ``_get_proxy_from_env`` reads
   ``HTTPS_PROXY`` / ``HTTP_PROXY`` / ``ALL_PROXY``;
   ``_get_proxy_for_base_url`` respects ``NO_PROXY`` for the given base URL.

``run_agent`` re-exports every name so existing
``from run_agent import _get_proxy_from_env`` imports keep working
unchanged.
    )annotationsN)AnyOptional)base_url_hostnamenormalize_proxy_urlreturntypec                 .    t           ddlm}  | a t           S )z#Import and cache ``openai.OpenAI``.Nr   )OpenAI)_OPENAI_CLS_CACHEopenair   )_clss    =/home/rurouni/.hermes/hermes-agent/agent/process_bootstrap.py_load_openai_clsr   '   s(      ))))))     c                  (    e Zd ZdZdZd Zd Zd ZdS )_OpenAIProxyzHModule-level proxy that looks like ``openai.OpenAI`` but imports lazily. c                *     t                      |i |S N)r   )selfargskwargss      r   __call__z_OpenAIProxy.__call__5   s    !!!426222r   c                :    t          |t                                S r   )
isinstancer   )r   objs     r   __instancecheck__z_OpenAIProxy.__instancecheck__8   s    #/11222r   c                    dS )Nz<lazy openai.OpenAI proxy>r   r   s    r   __repr__z_OpenAIProxy.__repr__;   s    ++r   N)__name__
__module____qualname____doc__	__slots__r   r   r!   r   r   r   r   r   0   sL        RRI3 3 33 3 3, , , , ,r   r   c                  :    e Zd ZdZdZd Zd Zd Zd Zd Z	d Z
d	S )
_SafeWriterup  Transparent stdio wrapper that catches OSError/ValueError from broken pipes.

    When hermes-agent runs as a systemd service, Docker container, or headless
    daemon, the stdout/stderr pipe can become unavailable (idle timeout, buffer
    exhaustion, socket reset). Any print() call then raises
    ``OSError: [Errno 5] Input/output error``, which can crash agent setup or
    run_conversation() — especially via double-fault when an except handler
    also tries to print.

    Additionally, when subagents run in ThreadPoolExecutor threads, the shared
    stdout handle can close between thread teardown and cleanup, raising
    ``ValueError: I/O operation on closed file`` instead of OSError.

    This wrapper delegates all writes to the underlying stream and silently
    catches both OSError and ValueError. It is transparent when the wrapped
    stream is healthy.
    )_innerc                >    t                               | d|           d S )Nr)   )object__setattr__)r   inners     r   __init__z_SafeWriter.__init__T   s     4511111r   c                    	 | j                             |          S # t          t          f$ r) t	          |t
                    rt          |          ndcY S w xY w)Nr   )r)   writeOSError
ValueErrorr   strlen)r   datas     r   r0   z_SafeWriter.writeW   sb    	=;$$T***$ 	= 	= 	= *4 5 5<3t9991<<<	=s    7AAc                j    	 | j                                          d S # t          t          f$ r Y d S w xY wr   )r)   flushr1   r2   r    s    r   r7   z_SafeWriter.flush]   sH    	K$ 	 	 	DD	s    22c                4    | j                                         S r   )r)   filenor    s    r   r9   z_SafeWriter.filenoc   s    {!!###r   c                f    	 | j                                         S # t          t          f$ r Y dS w xY w)NF)r)   isattyr1   r2   r    s    r   r;   z_SafeWriter.isattyf   sB    	;%%'''$ 	 	 	55	s    00c                ,    t          | j        |          S r   )getattrr)   )r   names     r   __getattr__z_SafeWriter.__getattr__l   s    t{D)))r   N)r"   r#   r$   r%   r&   r.   r0   r7   r9   r;   r?   r   r   r   r(   r(   ?   s         $ I2 2 2= = =  $ $ $  * * * * *r   r(   Optional[str]c                     dD ]G} t           j                            | d                                          }|rt	          |          c S HdS )zRead proxy URL from environment variables.

    Checks HTTPS_PROXY, HTTP_PROXY, ALL_PROXY (and lowercase variants) in order.
    Returns the first valid proxy URL found, or None if no proxy is configured.
    )HTTPS_PROXY
HTTP_PROXY	ALL_PROXYhttps_proxy
http_proxy	all_proxy N)osenvirongetstripr   )keyvalues     r   _get_proxy_from_envrO   p   sZ    : . .
sB''--// 	.&u-----	.4r   base_urlc                    t                      }|r| s|S t          |           }|s|S 	 t          j                            |          rdS n# t
          $ r Y nw xY w|S )zFReturn an env-configured proxy unless NO_PROXY excludes this base URL.N)rO   r   urllibrequestproxy_bypass_environment	Exception)rP   proxyhosts      r   _get_proxy_for_base_urlrX   ~   s    !!E  X&&D >22488 	4	    Ls   A 
AArH   FT)
async_modeverifyr3   rY   boolrZ   r   Optional[Any]c               L   	 ddl }t          |           }|                    ddd          }|                    dddd	          }|r|j        n|j        }|r|j        n|j        }i }	| ||
           ||
          d}	 |||||	pd|          S # t          $ r Y dS w xY w)a  Build an httpx client for OpenAI SDK calls with env-only proxy policy.

    Uses explicit ``HTTPS_PROXY`` / ``NO_PROXY`` env vars via
    ``_get_proxy_for_base_url``. Plain no-proxy mounts disable httpx's default
    ``trust_env`` proxy path, so macOS system proxy settings from
    ``urllib.request.getproxies()`` (which omit the ExceptionsList) are not
    applied. Mirrors ``AIAgent._build_keepalive_http_client``.

    Connection lifecycle is managed at the HTTP pool layer
    (``keepalive_expiry=20.0`` reaps idle connections before reverse proxies'
    typical 30-60 s timeouts) instead of the former custom
    ``socket_options`` transport, which broke streaming behind reverse
    proxies (#54049, #12952) and stalled TLS handshakes by stripping
    ``TCP_NODELAY``.

    ``verify`` is forwarded to httpx so auxiliary-client calls (compression,
    vision, web_extract, title generation, etc.) honor the same per-provider
    ``ssl_ca_cert`` / ``ssl_verify`` and ``HERMES_CA_BUNDLE`` settings the main
    client uses. It is passed on the client AND on the plain no-proxy mounts
    (a mounted transport owns the SSL context for its scheme).
    r   N   d   g      4@)max_keepalive_connectionsmax_connectionskeepalive_expiryg      .@g      $@)connectreadr0   pool)rZ   )zhttp://zhttps://)limitstimeoutrV   mountsrZ   )	httpxrX   LimitsTimeoutAsyncHTTPTransportHTTPTransportAsyncClientClientrU   )
rP   rY   rZ   ri   rV   rf   rg   transport_cls
client_clsrh   s
             r   build_keepalive_http_clientrr      s
   6'11&(!  
 
 --4t$-OO4>W00EDW*4FU&&%,
=(=777)M888 F z>T
 
 
 	
    tts   BB 
B#"B#Nonec                     dD ]R} t          t          | d          }|8t          |t                    s#t	          t          | t          |                     SdS )zHWrap stdout/stderr so best-effort console output cannot crash the agent.)stdoutstderrN)r=   sysr   r(   setattr)stream_namestreams     r   _install_safe_stdior{      s\    + ; ;k400j&E&ECk&&9&9:::; ;r   )r   r   r   r(   r{   rO   rX   rr   )r   r	   )r   r@   )rP   r@   r   r@   )rH   )rP   r3   rY   r[   rZ   r   r   r\   )r   rs   )r%   
__future__r   rI   rw   urllib.requestrR   typingr   r   utilsr   r   r   r   r   r(   rO   rX   rr   r{   r   __all__r   r   r   <module>r      sm   . # " " " " " 				 



                     8 8 8 8 8 8 8 8
     , , , , , , , ,.* .* .* .* .* .* .* .*b      ( 8 	8 8 8 8 8 8v; ; ; ; 
	 	 	r   