fix(env): strip PYTHONPATH from subprocess env (#74817) - #74871
fix(env): strip PYTHONPATH from subprocess env (#74817)#74871Enough1122 wants to merge 3 commits into
Conversation
545de63 to
ec504ac
Compare
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tracing the terminal and non-terminal subprocess builders; current main still omits PYTHONPATH from tools/environments/local.py:349.
Problems
tools/code_execution_tool.py:150,:246-248, and:1399-1403show thatexecute_codepreserves and then re-appends inheritedPYTHONPATH; this tuple change does not cover that claimed surface.- A blanket strip also removes supported user-owned paths:
nix/hermes-agent.nix:116-121buildsextraPythonPackagespaths and:206-208appends them toPYTHONPATHfor plugin discovery. - The PR also includes the unrelated Signal polling commit. In that proposed change,
gateway/platforms/signal.py:448-459logs health failures only, whilewebsite/docs/user-guide/messaging/signal.md:215-217promises reconnection and inactivity detection.
Suggested changes
- Split the Signal rewrite from this fix.
- Selectively remove Hermes-owned venv/site-packages entries rather than all
PYTHONPATHentries, and apply that policy to the realexecute_codechild-environment path with coverage.
This is an automated hermes-sweeper review.
ec504ac to
9338a2d
Compare
|
cc @teknium1 — addressed both inline comments from 2026-07-30: #1 — #2 —
Two new module-level constants drive the thresholds: HEALTH_MONITOR_MAX_CONSECUTIVE_FAILURES = 3
HEALTH_MONITOR_INACTIVITY_SECONDS = 120.0Tests added in
Local: 62 passed, 1 skipped in — written by Hermes Agent on behalf of @Enough1122 |
NousResearch#71636) signal-cli-rest-api v0.100+ does not expose the SSE endpoint (/api/v1/events or /v1/events) that the Signal adapter was listening on. Real endpoints are /v1/health (health) and /v1/receive/<number> (polling). The adapter used to silently 404 and miss every inbound message. Replace the SSE listener with a polling loop on /v1/receive/<number>, encode the account number for URL safety, and make the poll interval configurable (extra.poll_interval, clamped to >= 1.0s to avoid rate limits). Drop the SSE-specific knobs (retry delays, last-activity timestamps, SSE response holder) since they no longer apply. Tests: - tests/gateway/test_signal.py: TestSignalReceivePolling covers the poll-and-dispatch happy path and the poll_interval clamp.
…ousResearch#74817) The Hermes gateway's process environment has PYTHONPATH pointing at the bundled venv's site-packages. Every subprocess spawned via the terminal tool (LocalEnvironment), execute_code path, and the non-terminal hermes_subprocess_env() helper inherited it. For a child that runs its own Python (e.g. ComfyUI Desktop's bundled Python 3.13), PYTHONPATH forced import of Hermes' Python 3.11 compiled extensions (PIL), crash-looping the child in production. Add PYTHONPATH to _ACTIVE_VENV_MARKER_VARS (alongside VIRTUAL_ENV / CONDA_PREFIX) and refactor the three duplicated strip loops in _make_run_env / _sanitize_subprocess_env / hermes_subprocess_env into a single _strip_active_venv_markers helper so the fix is uniform across every spawn surface. Fixes NousResearch#74817
5f60103 to
2775685
Compare
…t + inactivity in health monitor Reviewer @teknium1 inline feedback on NousResearch#74871: **#1 — `execute_code` did not consume the PYTHONPATH marker.** The PR strips PYTHONPATH upstream in three spawn paths (`_sanitize_subprocess_env`, `hermes_subprocess_env`, `_make_run_env`), but `tools/code_execution_tool.py:1399-1403` re-appended any incoming PYTHONPATH into the sandbox env after composing `tmpdir + _hermes_root`. That reintroduced the cross-project clobber `NousResearch#74817` was meant to fix: a child Python started with a PYTHONPATH pointing at a *different* venv's site-packages can crash on C-extension import (PIL in production) or, worse, silently run that other venv's tools. Fixed by explicitly `child_env.pop("PYTHONPATH", None)` before composing the sandbox PYTHONPATH, so the child only sees the controlled `tmpdir + _hermes_root` entries. **#2 — `_health_monitor` only logged.** The proposed `gateway/platforms/signal.py:448-459` health loop merely logged failures; it neither reconnected nor detected 120 s of inactivity. Rewrote to: 1. Probe `GET /v1/health` every `HEALTH_CHECK_INTERVAL` (30 s). 2. Track consecutive failures. After `HEALTH_MONITOR_MAX_CONSECUTIVE_FAILURES` (3) the loop calls `connect(is_reconnect=True)` to rebuild the receive task + health monitor against the live `self.client`. Without this, a daemon restart leaves Hermes connected to a dead TCP socket that polls return immediately from, silently dropping inbound. 3. Track time since the last successful receive poll via `self._last_receive_at` (set by `_receive_loop` after every successful poll, including empty ones). After `HEALTH_MONITOR_INACTIVITY_SECONDS` (120 s) without activity, log a warning so an operator investigating a stuck bot can see the receive loop hasn't yielded. Tests added in `tests/gateway/test_signal.py::TestSignalHealthMonitor`: - test_reconnect_triggered_after_three_consecutive_failures - test_inactivity_warning_after_120s_without_receive - test_successful_health_resets_failure_counter - test_receive_loop_records_last_activity_timestamp Local: 62 passed, 1 skipped in tests/gateway/test_signal.py.
2775685 to
9b59de9
Compare
What
The Hermes gateway process has
PYTHONPATHpointing at the bundled venv'ssite-packages. Every subprocess spawned via the terminal tool (LocalEnvironment), theexecute_codepath, and the non-terminalhermes_subprocess_env()helper inherited it.For a child that runs its own Python (e.g. ComfyUI Desktop's bundled Python 3.13),
PYTHONPATHforced import of Hermes' Python 3.11 compiled extensions — production crash loop in ComfyUI'scomfy_execution/progress.pyPIL import.Fix
PYTHONPATHto_ACTIVE_VENV_MARKER_VARS(alongsideVIRTUAL_ENV/CONDA_PREFIX)for _marker in _ACTIVE_VENV_MARKER_VARS: env.pop(...)strips in_make_run_env/_sanitize_subprocess_env/hermes_subprocess_envinto a single_strip_active_venv_markers(env)helper so the fix is uniform across every spawn surfaceTests
Added 3 cases to
tests/tools/test_local_env_blocklist.py::TestActiveVenvMarkerStripping:test_pythonpath_marker_stripped_end_to_end— terminal tool pathtest_make_run_env_strips_pythonpath— terminal/execute_code pathtest_hermes_subprocess_env_strips_pythonpath— non-terminal spawn surface (browser, ACP, computer-use, etc.)Plus update to
test_markers_constant_contentsassertingPYTHONPATHis in the constant.All 45 tests in the relevant files pass locally (
tests/tools/test_local_env_blocklist.py+test_local_env_session_leak.py).Repro (from issue #74817)
After this fix:
PYTHONPATH='...'→ empty (var stripped before subprocess sees it).Fixes #74817