mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-19 10:02:16 +00:00
* feat(mcp): raise default tool-call timeout 120s -> 300s Port from openai/codex#28234. Long-running MCP tools (web fetches, sandboxed builds, deep-research servers) routinely exceed 120s, causing spurious timeout failures. Codex bumped its default MCP tool timeout from 120 to 300 for the same reason. - _DEFAULT_TOOL_TIMEOUT 120 -> 300 in tools/mcp_tool.py (per-server 'timeout' config override unchanged) - update test_default_timeout assertion - document the default in mcp-config-reference.md * fix(dump): show commit date instead of release date in hermes dump The version line in `hermes dump` (the top of the /debug report) appended the package release date in parentheses, which reads like a wall-clock "generated at" timestamp and confuses support triage. Replace it with the date the HEAD commit was actually made, resolved live via `git log -1 --format=%cd --date=short`, kept next to the commit SHA. On Docker/wheel installs with no .git the date resolves to '' and the suffix is simply omitted (the baked SHA still identifies the build).
159 lines
5.6 KiB
Python
159 lines
5.6 KiB
Python
"""Tests for hermes_cli.dump._get_git_commit — git SHA resolution for ``hermes dump``.
|
|
|
|
``hermes dump`` prints the running commit so support bug reports identify the
|
|
exact version. Source installs resolve it live via ``git rev-parse``; the
|
|
published Docker image excludes ``.git`` and falls back to the baked SHA
|
|
written by the Dockerfile's ``HERMES_GIT_SHA`` build-arg.
|
|
|
|
These tests cover both paths plus the failure modes (no git, no baked file).
|
|
"""
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
|
|
def test_get_git_commit_uses_live_git_when_available(tmp_path):
|
|
"""Source install: ``git rev-parse --short=8 HEAD`` wins; no fallback."""
|
|
from hermes_cli import dump
|
|
|
|
repo_dir = tmp_path / "repo"
|
|
repo_dir.mkdir()
|
|
|
|
git_result = MagicMock(returncode=0, stdout="deadbeef\n")
|
|
# build_info should NOT be consulted when live git succeeds.
|
|
with patch("hermes_cli.dump.subprocess.run", return_value=git_result) as mock_run, \
|
|
patch("hermes_cli.build_info.get_build_sha") as mock_build:
|
|
commit = dump._get_git_commit(repo_dir)
|
|
|
|
assert commit == "deadbeef"
|
|
mock_run.assert_called_once()
|
|
mock_build.assert_not_called()
|
|
|
|
|
|
def test_get_git_commit_falls_back_to_build_sha_when_live_git_fails(tmp_path):
|
|
"""Docker image case: live git returns non-zero → use baked SHA."""
|
|
from hermes_cli import dump
|
|
|
|
repo_dir = tmp_path / "no-git-here"
|
|
repo_dir.mkdir()
|
|
|
|
failed = MagicMock(returncode=128, stdout="")
|
|
with patch("hermes_cli.dump.subprocess.run", return_value=failed), \
|
|
patch("hermes_cli.build_info.get_build_sha", return_value="cafef00d"):
|
|
commit = dump._get_git_commit(repo_dir)
|
|
|
|
assert commit == "cafef00d"
|
|
|
|
|
|
def test_get_git_commit_falls_back_when_git_returns_empty_stdout(tmp_path):
|
|
"""Edge case: git exits 0 but prints nothing — still try the baked SHA."""
|
|
from hermes_cli import dump
|
|
|
|
repo_dir = tmp_path / "repo"
|
|
repo_dir.mkdir()
|
|
|
|
empty = MagicMock(returncode=0, stdout="\n")
|
|
with patch("hermes_cli.dump.subprocess.run", return_value=empty), \
|
|
patch("hermes_cli.build_info.get_build_sha", return_value="abcdef12"):
|
|
commit = dump._get_git_commit(repo_dir)
|
|
|
|
assert commit == "abcdef12"
|
|
|
|
|
|
def test_get_git_commit_falls_back_when_git_raises(tmp_path):
|
|
"""git binary missing (e.g. minimal container w/o git) → baked SHA path."""
|
|
from hermes_cli import dump
|
|
|
|
repo_dir = tmp_path / "repo"
|
|
repo_dir.mkdir()
|
|
|
|
with patch("hermes_cli.dump.subprocess.run", side_effect=FileNotFoundError("git")), \
|
|
patch("hermes_cli.build_info.get_build_sha", return_value="feedface"):
|
|
commit = dump._get_git_commit(repo_dir)
|
|
|
|
assert commit == "feedface"
|
|
|
|
|
|
def test_get_git_commit_returns_unknown_when_neither_source_available(tmp_path):
|
|
"""Pip-installed wheel: no git, no baked SHA → '(unknown)' (legacy contract)."""
|
|
from hermes_cli import dump
|
|
|
|
repo_dir = tmp_path / "repo"
|
|
repo_dir.mkdir()
|
|
|
|
failed = MagicMock(returncode=128, stdout="")
|
|
with patch("hermes_cli.dump.subprocess.run", return_value=failed), \
|
|
patch("hermes_cli.build_info.get_build_sha", return_value=None):
|
|
commit = dump._get_git_commit(repo_dir)
|
|
|
|
assert commit == "(unknown)"
|
|
|
|
|
|
def test_get_git_commit_output_format_identical_between_sources(tmp_path):
|
|
"""Regression guard: live-git and baked-SHA outputs share the same shape.
|
|
|
|
Ben explicitly asked for identical output between Docker and source installs
|
|
so support tooling that parses ``hermes dump`` doesn't have to special-case
|
|
container builds. Both paths must return a bare 8-char SHA — no prefix,
|
|
no suffix, no annotation.
|
|
"""
|
|
from hermes_cli import dump
|
|
|
|
repo_dir = tmp_path / "repo"
|
|
repo_dir.mkdir()
|
|
|
|
# Live-git path.
|
|
git_result = MagicMock(returncode=0, stdout="b2f477a3\n")
|
|
with patch("hermes_cli.dump.subprocess.run", return_value=git_result):
|
|
live = dump._get_git_commit(repo_dir)
|
|
|
|
# Baked-SHA path.
|
|
failed = MagicMock(returncode=128, stdout="")
|
|
with patch("hermes_cli.dump.subprocess.run", return_value=failed), \
|
|
patch("hermes_cli.build_info.get_build_sha", return_value="b2f477a3"):
|
|
baked = dump._get_git_commit(repo_dir)
|
|
|
|
assert live == baked == "b2f477a3"
|
|
# Same length, same charset — no decoration in either branch.
|
|
assert len(live) == 8
|
|
assert all(c in "0123456789abcdef" for c in live)
|
|
|
|
|
|
def test_get_git_commit_date_uses_live_git(tmp_path):
|
|
"""Source install: ``git log -1 --format=%cd --date=short`` returns the date."""
|
|
from hermes_cli import dump
|
|
|
|
repo_dir = tmp_path / "repo"
|
|
repo_dir.mkdir()
|
|
|
|
git_result = MagicMock(returncode=0, stdout="2026-06-17\n")
|
|
with patch("hermes_cli.dump.subprocess.run", return_value=git_result):
|
|
date = dump._get_git_commit_date(repo_dir)
|
|
|
|
assert date == "2026-06-17"
|
|
|
|
|
|
def test_get_git_commit_date_empty_when_git_fails(tmp_path):
|
|
"""Docker image / pip wheel: no git → '' so the dump line drops the date."""
|
|
from hermes_cli import dump
|
|
|
|
repo_dir = tmp_path / "no-git-here"
|
|
repo_dir.mkdir()
|
|
|
|
failed = MagicMock(returncode=128, stdout="")
|
|
with patch("hermes_cli.dump.subprocess.run", return_value=failed):
|
|
date = dump._get_git_commit_date(repo_dir)
|
|
|
|
assert date == ""
|
|
|
|
|
|
def test_get_git_commit_date_empty_when_git_raises(tmp_path):
|
|
"""git binary missing → '' (no crash, suffix simply omitted)."""
|
|
from hermes_cli import dump
|
|
|
|
repo_dir = tmp_path / "repo"
|
|
repo_dir.mkdir()
|
|
|
|
with patch("hermes_cli.dump.subprocess.run", side_effect=FileNotFoundError("git")):
|
|
date = dump._get_git_commit_date(repo_dir)
|
|
|
|
assert date == ""
|