mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-23 16:36:23 +00:00
fix(gateway): report runtime source version in /health, not stale dist-info metadata
/health and /health/detailed resolve the version via importlib.metadata first, falling back to hermes_cli.__version__. On editable/source checkouts — including the standard git-based install that hermes-setup performs — hermes_agent-*.dist-info can survive a source update unchanged, so the health endpoints keep reporting the previous release even though the running code (CLI, dashboard, release tags) is newer. Stale metadata does not raise, so the source fallback never fires. Flip the preference: use hermes_cli.__version__ (the runtime source of truth shared by the CLI and dashboard) first, and fall back to distribution metadata only when the source import fails. The never-raise contract of the version probe is unchanged. Observed live: CLI, dashboard, and pyproject all reported 0.18.2 while /health returned 0.18.0 from a stale hermes_agent-0.18.0.dist-info left behind by a source update. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
87e31cb7d1
commit
eff293115d
2 changed files with 37 additions and 11 deletions
|
|
@ -96,23 +96,25 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
|
||||
def _hermes_version() -> str:
|
||||
"""Return the hermes-agent version string, or "dev" if it can't be resolved.
|
||||
"""Return the canonical Hermes Agent version string.
|
||||
|
||||
Tries the installed package metadata first (authoritative for a pip/uv
|
||||
install), then the in-tree ``hermes_cli.__version__`` (covers editable /
|
||||
source checkouts where metadata may be stale or absent). Never raises —
|
||||
a version probe must not be able to break the health endpoint.
|
||||
``hermes_cli.__version__`` is the runtime source of truth used by the CLI,
|
||||
dashboard, portal tags, and release script. Prefer it over installed
|
||||
distribution metadata because editable/source checkouts can retain stale
|
||||
``hermes_agent-*.dist-info`` after a source update until the environment is
|
||||
reinstalled. Never raises — a version probe must not be able to break the
|
||||
health endpoint.
|
||||
"""
|
||||
try:
|
||||
from importlib.metadata import version
|
||||
|
||||
return version("hermes-agent")
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
from hermes_cli import __version__
|
||||
|
||||
return __version__
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
from importlib.metadata import version
|
||||
|
||||
return version("hermes-agent")
|
||||
except Exception:
|
||||
return "dev"
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ from gateway.platforms.api_server import (
|
|||
ResponseStore,
|
||||
_IdempotencyCache,
|
||||
_derive_chat_session_id,
|
||||
_hermes_version,
|
||||
_redact_api_error_text,
|
||||
check_api_server_requirements,
|
||||
cors_middleware,
|
||||
|
|
@ -776,6 +777,29 @@ class TestHealthEndpoint:
|
|||
assert isinstance(data["version"], str)
|
||||
assert data["version"] != ""
|
||||
|
||||
def test_health_version_prefers_runtime_source_over_stale_metadata(self):
|
||||
"""Editable installs can leave importlib.metadata at an older release.
|
||||
|
||||
The health endpoint must report the running Hermes source version, not
|
||||
stale ``hermes_agent-*.dist-info`` metadata from before a source update.
|
||||
"""
|
||||
from hermes_cli import __version__
|
||||
|
||||
with patch("importlib.metadata.version", return_value="0.18.0"):
|
||||
assert _hermes_version() == __version__
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_health_endpoint_prefers_runtime_version_over_stale_metadata(self, adapter):
|
||||
from hermes_cli import __version__
|
||||
|
||||
app = _create_app(adapter)
|
||||
with patch("importlib.metadata.version", return_value="0.18.0"):
|
||||
async with TestClient(TestServer(app)) as cli:
|
||||
resp = await cli.get("/health")
|
||||
assert resp.status == 200
|
||||
data = await resp.json()
|
||||
assert data["version"] == __version__
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_v1_health_alias_returns_ok(self, adapter):
|
||||
"""GET /v1/health should return the same response as /health."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue