fix(terminal): strip Hermes-venv site-packages from terminal subprocess PYTHONPATH to prevent cross-version ABI conflicts

The Desktop Electron process injects the Hermes venv's site-packages path
(e.g. .../python3.11/site-packages) into PYTHONPATH so the Python 3.11
backend can import its packages. When this PYTHONPATH leaks into terminal
subprocesses running a different Python version (e.g. Python 3.13), 3.11
C extension modules appear on sys.path ahead of the correct 3.13 versions
and crash with ImportError (PIL _imaging, cryptography, etc.).

Replace the existing blunt pop of PYTHONPATH from _ACTIVE_VENV_MARKER_VARS
with a surgical Hermes-venv-aware filter:

- Parse each PYTHONPATH entry by path
- Strip only paths under ~/.hermes/hermes-agent/venv/.../site-packages
- Preserve the Hermes source root (needed for import hermes_cli)
- Preserve all user-set PYTHONPATH entries

The same filter is applied in all three env builders:
- _make_run_env (foreground terminal commands)
- _sanitize_subprocess_env (background/PTY spawns)
- PTY env builder

This preserves env_passthrough semantics and never silently discards the
user's own PYTHONPATH configuration.
This commit is contained in:
mcjoys
2026-07-09 00:53:12 +08:00
committed by Teknium
parent 93ed11379b
commit 43c463fa95
3 changed files with 468 additions and 0 deletions
+10
View File
@@ -1483,6 +1483,16 @@ def execute_code(
# external venv; exposing Hermes's site-packages to that interpreter
# can mix incompatible compiled extensions (for example, Python 3.12
# NumPy with a Python 3.9 project interpreter).
# Before re-injecting PYTHONPATH, strip any mismatched site-packages
# entries that leaked through _scrub_child_env (PYTHONPATH is in
# _SAFE_ENV_PREFIXES so it passes the scrub). Cross-version entries
# (e.g. python3.11 site-packages injected by systemd/Electron) would
# poison the sandbox's sys.path with ABI-incompatible C extensions
# (#74817); Hermes venv/repo-root entries are redundant because the
# correct ones are re-added below, gated on the child interpreter
# actually being the Hermes environment.
from tools.environments.local import _strip_mismatched_site_packages
_strip_mismatched_site_packages(child_env)
_hermes_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_existing_pp = child_env.get("PYTHONPATH", "")
_pp_parts = [tmpdir]