diff --git a/gateway/platforms/api_server.py b/gateway/platforms/api_server.py index 973ba5507379..e0629d270d90 100644 --- a/gateway/platforms/api_server.py +++ b/gateway/platforms/api_server.py @@ -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" diff --git a/tests/gateway/test_api_server.py b/tests/gateway/test_api_server.py index 56734698019a..7700cec107d0 100644 --- a/tests/gateway/test_api_server.py +++ b/tests/gateway/test_api_server.py @@ -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."""