mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-30 01:41:43 +00:00
fix(config): respect quoted false for session vacuum_after_prune
This commit is contained in:
parent
4fade39c90
commit
7da299ddb0
6 changed files with 94 additions and 15 deletions
4
cli.py
4
cli.py
|
|
@ -77,7 +77,7 @@ _COMMAND_SPINNER_FRAMES = ("⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧
|
|||
# User-managed env files should override stale shell exports on restart.
|
||||
from hermes_constants import get_hermes_home, display_hermes_home
|
||||
from hermes_cli.env_loader import load_hermes_dotenv
|
||||
from utils import base_url_host_matches
|
||||
from utils import base_url_host_matches, coerce_bool
|
||||
|
||||
_hermes_home = get_hermes_home()
|
||||
_project_env = Path(__file__).parent / '.env'
|
||||
|
|
@ -974,7 +974,7 @@ def _run_state_db_auto_maintenance(session_db) -> None:
|
|||
session_db.maybe_auto_prune_and_vacuum(
|
||||
retention_days=int(cfg.get("retention_days", 90)),
|
||||
min_interval_hours=int(cfg.get("min_interval_hours", 24)),
|
||||
vacuum=bool(cfg.get("vacuum_after_prune", True)),
|
||||
vacuum=coerce_bool(cfg.get("vacuum_after_prune", True), default=True),
|
||||
)
|
||||
except Exception as exc:
|
||||
logger.debug("state.db auto-maintenance skipped: %s", exc)
|
||||
|
|
|
|||
|
|
@ -17,23 +17,14 @@ from typing import Dict, List, Optional, Any
|
|||
from enum import Enum
|
||||
|
||||
from hermes_cli.config import get_hermes_home
|
||||
from utils import is_truthy_value
|
||||
from utils import coerce_bool
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _coerce_bool(value: Any, default: bool = True) -> bool:
|
||||
"""Coerce bool-ish config values, preserving a caller-provided default."""
|
||||
if value is None:
|
||||
return default
|
||||
if isinstance(value, str):
|
||||
lowered = value.strip().lower()
|
||||
if lowered in ("true", "1", "yes", "on"):
|
||||
return True
|
||||
if lowered in ("false", "0", "no", "off"):
|
||||
return False
|
||||
return default
|
||||
return is_truthy_value(value, default=default)
|
||||
return coerce_bool(value, default=default)
|
||||
|
||||
|
||||
def _normalize_unauthorized_dm_behavior(value: Any, default: str = "pair") -> str:
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ sys.path.insert(0, str(Path(__file__).parent.parent))
|
|||
|
||||
# Resolve Hermes home directory (respects HERMES_HOME override)
|
||||
from hermes_constants import get_hermes_home
|
||||
from utils import atomic_yaml_write, base_url_host_matches, is_truthy_value
|
||||
from utils import atomic_yaml_write, base_url_host_matches, coerce_bool, is_truthy_value
|
||||
_hermes_home = get_hermes_home()
|
||||
|
||||
# Load environment variables from ~/.hermes/.env first.
|
||||
|
|
@ -748,7 +748,7 @@ class GatewayRunner:
|
|||
self._session_db.maybe_auto_prune_and_vacuum(
|
||||
retention_days=int(_sess_cfg.get("retention_days", 90)),
|
||||
min_interval_hours=int(_sess_cfg.get("min_interval_hours", 24)),
|
||||
vacuum=bool(_sess_cfg.get("vacuum_after_prune", True)),
|
||||
vacuum=coerce_bool(_sess_cfg.get("vacuum_after_prune", True), default=True),
|
||||
)
|
||||
except Exception as exc:
|
||||
logger.debug("state.db auto-maintenance skipped: %s", exc)
|
||||
|
|
|
|||
31
tests/cli/test_state_db_auto_maintenance.py
Normal file
31
tests/cli/test_state_db_auto_maintenance.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize("raw_value", ["false", False])
|
||||
def test_run_state_db_auto_maintenance_respects_vacuum_flag(monkeypatch, tmp_path, raw_value):
|
||||
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
|
||||
|
||||
import cli as cli_mod
|
||||
|
||||
session_db = Mock()
|
||||
monkeypatch.setattr(
|
||||
"hermes_cli.config.load_config",
|
||||
lambda: {
|
||||
"sessions": {
|
||||
"auto_prune": True,
|
||||
"retention_days": 30,
|
||||
"min_interval_hours": 12,
|
||||
"vacuum_after_prune": raw_value,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
cli_mod._run_state_db_auto_maintenance(session_db)
|
||||
|
||||
session_db.maybe_auto_prune_and_vacuum.assert_called_once_with(
|
||||
retention_days=30,
|
||||
min_interval_hours=12,
|
||||
vacuum=False,
|
||||
)
|
||||
34
tests/gateway/test_state_db_auto_maintenance.py
Normal file
34
tests/gateway/test_state_db_auto_maintenance.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from gateway.config import GatewayConfig
|
||||
from gateway.run import GatewayRunner
|
||||
|
||||
|
||||
@pytest.mark.parametrize("raw_value", ["false", False])
|
||||
def test_gateway_runner_respects_vacuum_after_prune_flag(monkeypatch, tmp_path, raw_value):
|
||||
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
|
||||
|
||||
fake_db = Mock()
|
||||
monkeypatch.setattr("hermes_state.SessionDB", lambda: fake_db)
|
||||
monkeypatch.setattr(
|
||||
"hermes_cli.config.load_config",
|
||||
lambda: {
|
||||
"sessions": {
|
||||
"auto_prune": True,
|
||||
"retention_days": 45,
|
||||
"min_interval_hours": 6,
|
||||
"vacuum_after_prune": raw_value,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
runner = GatewayRunner(GatewayConfig(sessions_dir=tmp_path / "sessions"))
|
||||
|
||||
assert runner._session_db is fake_db
|
||||
fake_db.maybe_auto_prune_and_vacuum.assert_called_once_with(
|
||||
retention_days=45,
|
||||
min_interval_hours=6,
|
||||
vacuum=False,
|
||||
)
|
||||
23
utils.py
23
utils.py
|
|
@ -15,6 +15,7 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
|
||||
TRUTHY_STRINGS = frozenset({"1", "true", "yes", "on"})
|
||||
FALSY_STRINGS = frozenset({"0", "false", "no", "off"})
|
||||
|
||||
|
||||
def is_truthy_value(value: Any, default: bool = False) -> bool:
|
||||
|
|
@ -28,6 +29,28 @@ def is_truthy_value(value: Any, default: bool = False) -> bool:
|
|||
return bool(value)
|
||||
|
||||
|
||||
def coerce_bool(value: Any, default: bool = False) -> bool:
|
||||
"""Coerce bool-ish config values while preserving the caller's default.
|
||||
|
||||
Unlike ``bool(value)``, this treats quoted config strings like
|
||||
``"false"`` and ``"0"`` as ``False`` instead of truthy non-empty
|
||||
strings. Unrecognized strings fall back to ``default`` so malformed
|
||||
YAML values don't silently flip behavior.
|
||||
"""
|
||||
if value is None:
|
||||
return default
|
||||
if isinstance(value, bool):
|
||||
return value
|
||||
if isinstance(value, str):
|
||||
lowered = value.strip().lower()
|
||||
if lowered in TRUTHY_STRINGS:
|
||||
return True
|
||||
if lowered in FALSY_STRINGS:
|
||||
return False
|
||||
return default
|
||||
return bool(value)
|
||||
|
||||
|
||||
def env_var_enabled(name: str, default: str = "") -> bool:
|
||||
"""Return True when an environment variable is set to a truthy value."""
|
||||
return is_truthy_value(os.getenv(name, default), default=False)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue