mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 05:17:15 +00:00
fix(agent): agent builds no longer wrap the thread-routing stdio proxy
_install_safe_stdio() only skipped a _SafeWriter, so after a background review installed the thread-routing proxy, the next agent build wrapped that proxy in a _SafeWriter. The next thread_scoped_silence() no longer saw a router on top and installed a new one over the wrapper, so every build/silence cycle added two links to sys.stdout and sys.stderr. After about 500 cycles, the line-buffering probe in setup_logging hit RecursionError and every gateway turn failed until a restart. The routing proxy already absorbs the OSError/ValueError the _SafeWriter guards against, so the build now leaves it alone. The chain stays at one link (two with startup redaction) however many agents are built. Fixes #139687 Co-authored-by: X9A81P4 <156729876+X9A81P4@users.noreply.github.com> Co-authored-by: salch-cred <salch-cred@users.noreply.github.com>
This commit is contained in:
1 parent
67481b6f37
commit
05a32542ea
2 files changed
+23
-1
No files matched your search
@@ -18,6 +18,7 @@ from typing import Any, Optional
|
||||
from hermes_bootstrap import _happy_eyeballs_create_connection
|
||||
from utils import base_url_hostname, normalize_proxy_url
|
||||
from agent.proxy_bypass import first_proxy_env_value, should_bypass_proxy
|
||||
from agent.thread_scoped_output import _ThreadRoutingStream
|
||||
|
||||
|
||||
_OPENAI_CLS_CACHE = None
|
||||
@@ -334,7 +335,8 @@ def _install_safe_stdio() -> None:
|
||||
"""Wrap stdout/stderr so best-effort console output cannot crash the agent."""
|
||||
for stream_name in ("stdout", "stderr"):
|
||||
stream = getattr(sys, stream_name, None)
|
||||
if stream is not None and not isinstance(stream, _SafeWriter):
|
||||
# The routing proxy already absorbs these errors; wrapping it stacks a new proxy per build (#139687).
|
||||
if stream is not None and not isinstance(stream, (_SafeWriter, _ThreadRoutingStream)):
|
||||
setattr(sys, stream_name, _SafeWriter(stream))
|
||||
|
||||
|
||||
|
||||
@@ -130,6 +130,26 @@ def test_temporary_global_redirects_do_not_allocate_new_sinks(monkeypatch):
|
||||
sys.stdout, sys.stderr = original_stdout, original_stderr
|
||||
|
||||
|
||||
def test_agent_builds_keep_the_installed_routing_proxy(monkeypatch):
|
||||
"""Agent builds between silences must not stack wrappers on sys.stdout/stderr (#139687)."""
|
||||
from agent.process_bootstrap import _install_safe_stdio
|
||||
|
||||
monkeypatch.setattr(thread_output, "_installed", {})
|
||||
monkeypatch.setattr(sys, "stdout", io.StringIO())
|
||||
monkeypatch.setattr(sys, "stderr", io.StringIO())
|
||||
_install_safe_stdio()
|
||||
with thread_scoped_silence():
|
||||
pass
|
||||
routers = (sys.stdout, sys.stderr)
|
||||
|
||||
for _ in range(3):
|
||||
_install_safe_stdio()
|
||||
with thread_scoped_silence():
|
||||
pass
|
||||
|
||||
assert (sys.stdout, sys.stderr) == routers
|
||||
|
||||
|
||||
def test_silence_survives_redirect_restoring_an_older_proxy(monkeypatch):
|
||||
"""Silencing is stream-wide, even when a redirect swaps proxy generations."""
|
||||
monkeypatch.setattr(thread_output, "_installed", {})
|
||||
|
||||
Reference in new issue
Block a user