Files
hermes-agent/hermes_cli/local_runtime/__init__.py
alt-glitch 53fefae5d7 fix(local-runtime): hermes update from v2026.9.24 no longer crashes importing local_runtime
After the pull, the v2026.9.24 updater lazily imports
hermes_cli.local_runtime.processes (in _subprocess_compat.bounded_probe_run)
from the new checkout. Its process still holds the old
hermes_platform.host.facts. The package __init__ eagerly imported every
submodule, so hardware.py ran `from hermes_platform.host.facts import
gpu_class` (added in 827f4ff1d1) against the old facts module, and the
update died with ImportError. This broke e2e-upgrade (core) on main and
on every PR.

The package-level re-exports now resolve on first access through a module
__getattr__, so importing one submodule runs only that submodule. Callers
of `hermes_cli.local_runtime.<name>` are unchanged.
2026-10-06 20:11:00 -04:00

44 lines
2.0 KiB
Python

"""Managed llama.cpp runtime.
``binaries`` answers which backend this machine uses and which PM-pinned
engine is installed (the engine bytes live in pm's machine-wide store);
``bootstrap`` boots the managed server from what is installed — never a
download; ``supervisor`` spawns and supervises one llama-server in router
mode (readiness is a touch generation, never health-200 alone); ``detect``
finds an already-running llama-server (external or ours).
The package-level names resolve on first access. Shipped updaters import
``hermes_cli.local_runtime.processes`` from the NEW checkout after the pull,
while their process still holds the OLD ``hermes_platform`` and other
first-party modules. An eager re-export here would run every submodule
against those stale modules and crash the update on any name added since.
"""
from importlib import import_module
_EXPORTS = {
"binaries": ("BACKEND_PACKAGES", "BinaryResolutionError", "Engine", "ensure_engine",
"installed_engine", "pinned_tag", "resolve_backend", "select_backend"),
"bootstrap": ("ensure_local_runtime", "shutdown_local_runtime"),
"context_policy": ("FLOOR", "growth_decision", "initial_window", "ladder", "launch_args"),
"growth": ("clear_window_override", "load_window_overrides", "maybe_grow_window",
"save_window_override"),
"detect": ("detect_server",),
"endpoint": ("resolve_llamacpp_endpoint",),
"estimator": ("HardwareBudget", "ctx_bytes", "physics_check", "profile_from_gguf"),
"gguf": ("read_gguf_header",),
"hardware": ("probe_budget",),
"presets": ("generate_presets",),
"supervisor": ("LlamaServerSupervisor",),
}
_SOURCE = {name: module for module, names in _EXPORTS.items() for name in names}
def __getattr__(name: str):
module = _SOURCE.get(name)
if module is None:
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
value = getattr(import_module(f"{__name__}.{module}"), name)
globals()[name] = value
return value