mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-08 03:01:47 +00:00
fix(gateway): preserve max turns after env reload
This commit is contained in:
parent
2c14d3b9b0
commit
8308d18339
2 changed files with 86 additions and 7 deletions
|
|
@ -299,6 +299,36 @@ _env_path = _hermes_home / '.env'
|
|||
load_hermes_dotenv(hermes_home=_hermes_home, project_env=Path(__file__).resolve().parents[1] / '.env')
|
||||
|
||||
|
||||
def _reload_runtime_env_preserving_config_authority() -> None:
|
||||
"""Reload .env for fresh credentials without letting stale .env override config.
|
||||
|
||||
Gateway processes are long-lived, so per-turn code reloads ~/.hermes/.env to
|
||||
pick up rotated API keys. config.yaml remains authoritative for agent budget
|
||||
settings such as agent.max_turns; otherwise a stale HERMES_MAX_ITERATIONS in
|
||||
.env can replace the startup bridge on later turns.
|
||||
"""
|
||||
load_hermes_dotenv(
|
||||
hermes_home=_hermes_home,
|
||||
project_env=Path(__file__).resolve().parents[1] / '.env',
|
||||
)
|
||||
|
||||
config_path = _hermes_home / 'config.yaml'
|
||||
if not config_path.exists():
|
||||
return
|
||||
try:
|
||||
import yaml as _yaml
|
||||
with open(config_path, encoding="utf-8") as f:
|
||||
cfg = _yaml.safe_load(f) or {}
|
||||
from hermes_cli.config import _expand_env_vars
|
||||
cfg = _expand_env_vars(cfg)
|
||||
except Exception:
|
||||
return
|
||||
|
||||
agent_cfg = cfg.get("agent", {})
|
||||
if isinstance(agent_cfg, dict) and "max_turns" in agent_cfg:
|
||||
os.environ["HERMES_MAX_ITERATIONS"] = str(agent_cfg["max_turns"])
|
||||
|
||||
|
||||
_DOCKER_VOLUME_SPEC_RE = re.compile(r"^(?P<host>.+):(?P<container>/[^:]+?)(?::(?P<options>[^:]+))?$")
|
||||
_DOCKER_MEDIA_OUTPUT_CONTAINER_PATHS = {"/output", "/outputs"}
|
||||
|
||||
|
|
@ -13524,13 +13554,9 @@ class GatewayRunner:
|
|||
combined_ephemeral = (combined_ephemeral + "\n\n" + self._ephemeral_system_prompt).strip()
|
||||
|
||||
# Re-read .env and config for fresh credentials (gateway is long-lived,
|
||||
# keys may change without restart).
|
||||
try:
|
||||
load_dotenv(_env_path, override=True, encoding="utf-8")
|
||||
except UnicodeDecodeError:
|
||||
load_dotenv(_env_path, override=True, encoding="latin-1")
|
||||
except Exception:
|
||||
pass
|
||||
# keys may change without restart). Keep config.yaml authoritative for
|
||||
# runtime budget settings bridged into env vars.
|
||||
_reload_runtime_env_preserving_config_authority()
|
||||
|
||||
try:
|
||||
model, runtime_kwargs = self._resolve_session_agent_runtime(
|
||||
|
|
|
|||
53
tests/gateway/test_runtime_env_reload_config_authority.py
Normal file
53
tests/gateway/test_runtime_env_reload_config_authority.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
"""Regression tests for gateway per-turn env reload preserving config authority.
|
||||
|
||||
Issue #19158: startup bridges config.yaml agent.max_turns into
|
||||
HERMES_MAX_ITERATIONS, but a later per-turn load_dotenv(..., override=True)
|
||||
can restore a stale .env HERMES_MAX_ITERATIONS value before the next turn.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
from gateway import run as gateway_run
|
||||
|
||||
|
||||
def test_reload_runtime_env_preserves_config_max_turns(tmp_path: Path, monkeypatch) -> None:
|
||||
hermes_home = tmp_path / ".hermes"
|
||||
hermes_home.mkdir()
|
||||
(hermes_home / "config.yaml").write_text(
|
||||
yaml.safe_dump({"agent": {"max_turns": 9000}}),
|
||||
encoding="utf-8",
|
||||
)
|
||||
(hermes_home / ".env").write_text(
|
||||
"HERMES_MAX_ITERATIONS=90\nOPENROUTER_API_KEY=fresh-key\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
monkeypatch.setattr(gateway_run, "_hermes_home", hermes_home)
|
||||
monkeypatch.setenv("HERMES_MAX_ITERATIONS", "9000")
|
||||
monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
|
||||
|
||||
gateway_run._reload_runtime_env_preserving_config_authority()
|
||||
|
||||
assert os.environ["OPENROUTER_API_KEY"] == "fresh-key"
|
||||
assert os.environ["HERMES_MAX_ITERATIONS"] == "9000"
|
||||
|
||||
|
||||
def test_reload_runtime_env_keeps_env_max_iterations_when_config_omits_key(
|
||||
tmp_path: Path, monkeypatch
|
||||
) -> None:
|
||||
hermes_home = tmp_path / ".hermes"
|
||||
hermes_home.mkdir()
|
||||
(hermes_home / "config.yaml").write_text(yaml.safe_dump({"agent": {}}), encoding="utf-8")
|
||||
(hermes_home / ".env").write_text("HERMES_MAX_ITERATIONS=123\n", encoding="utf-8")
|
||||
|
||||
monkeypatch.setattr(gateway_run, "_hermes_home", hermes_home)
|
||||
monkeypatch.delenv("HERMES_MAX_ITERATIONS", raising=False)
|
||||
|
||||
gateway_run._reload_runtime_env_preserving_config_authority()
|
||||
|
||||
assert os.environ["HERMES_MAX_ITERATIONS"] == "123"
|
||||
Loading…
Add table
Add a link
Reference in a new issue