mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-18 04:41:56 +00:00
fix(background-review): silence memory provider teardown output leak
Background review fork redirected stdout/stderr around run_conversation() so its iteration messages stay silent. But the memory-provider teardown (shutdown_memory_provider() and review_agent.close()) fired in the outer finally block AFTER the redirect_stdout context exited — so provider teardown prints (Honcho disconnect, Hindsight sync, etc.) leaked into the parent terminal at end of every turn. Moves the teardown inside the redirect_stdout scope on the success path (and nulls review_agent so the finally safety-net skips double-shutdown). The finally block is rewritten as an exception-path safety net that re-opens a devnull redirect, since the original 'with' context has already exited by the time finally runs. Salvage of #25342 by @ayushere (manually re-applied + merged conflict with current main's set_thread_tool_whitelist wiring).
This commit is contained in:
parent
7becb19ea0
commit
55ba02befb
1 changed files with 30 additions and 13 deletions
43
run_agent.py
43
run_agent.py
|
|
@ -4373,6 +4373,20 @@ class AIAgent:
|
|||
finally:
|
||||
clear_thread_tool_whitelist()
|
||||
|
||||
# Tear down memory providers while stdout is still
|
||||
# redirected so background thread teardown (Honcho flush,
|
||||
# Hindsight sync, etc.) stays silent. The finally block
|
||||
# below is a safety net for the exception path.
|
||||
try:
|
||||
review_agent.shutdown_memory_provider()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
review_agent.close()
|
||||
except Exception:
|
||||
pass
|
||||
review_agent = None
|
||||
|
||||
# Scan the review agent's messages for successful tool actions
|
||||
# and surface a compact summary to the user. Tool messages
|
||||
# already present in messages_snapshot must be skipped, since
|
||||
|
|
@ -4402,21 +4416,24 @@ class AIAgent:
|
|||
logger.warning("Background memory/skill review failed: %s", e)
|
||||
self._emit_auxiliary_failure("background review", e)
|
||||
finally:
|
||||
# Background review agents can initialize memory providers
|
||||
# (for example Hindsight) that own their own network clients.
|
||||
# Explicitly stop those providers before closing the agent so
|
||||
# their aiohttp sessions do not leak until GC/process exit.
|
||||
# Then close all remaining resources (httpx client,
|
||||
# subprocesses, etc.) so GC doesn't try to clean them up on a
|
||||
# dead asyncio event loop (which produces "Event loop is
|
||||
# closed" errors).
|
||||
# Safety-net cleanup for the exception path. Normal
|
||||
# completion already shut down inside redirect_stdout above.
|
||||
# Re-open devnull here so any teardown output (Honcho flush,
|
||||
# Hindsight sync, background thread joins) stays silent even
|
||||
# on the exception path where redirect_stdout already exited.
|
||||
if review_agent is not None:
|
||||
try:
|
||||
review_agent.shutdown_memory_provider()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
review_agent.close()
|
||||
with open(os.devnull, "w", encoding="utf-8") as _fn, \
|
||||
contextlib.redirect_stdout(_fn), \
|
||||
contextlib.redirect_stderr(_fn):
|
||||
try:
|
||||
review_agent.shutdown_memory_provider()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
review_agent.close()
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
# Clear the approval callback on this bg-review thread so a
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue