refactor: migrate 10 config.yaml inline loaders to read_raw_config()

Replace 10 callsites across 6 files that manually opened config.yaml,
called yaml.safe_load(), and handled missing-file/parse-error fallbacks
with the new read_raw_config() helper from hermes_cli/config.py.

Each migrated site previously had 5-8 lines of boilerplate:
    config_path = get_hermes_home() / 'config.yaml'
    if config_path.exists():
        import yaml
        with open(config_path) as f:
            cfg = yaml.safe_load(f) or {}

Now reduced to:
    from hermes_cli.config import read_raw_config
    cfg = read_raw_config()

Migrated files:
- tools/browser_tool.py (4 sites): command_timeout, cloud_provider,
  allow_private_urls, record_sessions
- tools/env_passthrough.py: terminal.env_passthrough
- tools/credential_files.py: terminal.credential_files
- tools/transcription_tools.py: stt.model
- hermes_cli/commands.py: config-gated command resolution
- hermes_cli/auth.py (2 sites): model config read + provider reset

Skipped (intentionally):
- gateway/run.py: 10+ sites with local aliases, critical path
- hermes_cli/profiles.py: profile-specific config path
- hermes_cli/doctor.py: reads raw then writes fixes back
- agent/model_metadata.py: different file (context_length_cache.yaml)
- tools/website_policy.py: custom config_path param + error types
This commit is contained in:
Teknium 2026-04-07 17:28:04 -07:00
parent 0d41fb0827
commit b1a66d55b4
No known key found for this signature in database
6 changed files with 68 additions and 114 deletions

View file

@ -37,7 +37,7 @@ from typing import Any, Dict, List, Optional
import httpx import httpx
import yaml import yaml
from hermes_cli.config import get_hermes_home, get_config_path from hermes_cli.config import get_hermes_home, get_config_path, read_raw_config
from hermes_constants import OPENROUTER_BASE_URL from hermes_constants import OPENROUTER_BASE_URL
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -2214,14 +2214,7 @@ def _update_config_for_provider(
config_path = get_config_path() config_path = get_config_path()
config_path.parent.mkdir(parents=True, exist_ok=True) config_path.parent.mkdir(parents=True, exist_ok=True)
config: Dict[str, Any] = {} config = read_raw_config()
if config_path.exists():
try:
loaded = yaml.safe_load(config_path.read_text()) or {}
if isinstance(loaded, dict):
config = loaded
except Exception:
config = {}
current_model = config.get("model") current_model = config.get("model")
if isinstance(current_model, dict): if isinstance(current_model, dict):
@ -2258,12 +2251,8 @@ def _reset_config_provider() -> Path:
if not config_path.exists(): if not config_path.exists():
return config_path return config_path
try: config = read_raw_config()
config = yaml.safe_load(config_path.read_text()) or {} if not config:
except Exception:
return config_path
if not isinstance(config, dict):
return config_path return config_path
model = config.get("model") model = config.get("model")

View file

@ -293,14 +293,8 @@ def _resolve_config_gates() -> set[str]:
if not gated: if not gated:
return set() return set()
try: try:
import yaml from hermes_cli.config import read_raw_config
from hermes_constants import get_hermes_home cfg = read_raw_config()
config_path = str(get_hermes_home() / "config.yaml")
if os.path.exists(config_path):
with open(config_path, encoding="utf-8") as f:
cfg = yaml.safe_load(f) or {}
else:
cfg = {}
except Exception: except Exception:
return set() return set()
result: set[str] = set() result: set[str] = set()

View file

@ -146,15 +146,11 @@ def _get_command_timeout() -> int:
``DEFAULT_COMMAND_TIMEOUT`` (30s) if unset or unreadable. ``DEFAULT_COMMAND_TIMEOUT`` (30s) if unset or unreadable.
""" """
try: try:
hermes_home = get_hermes_home() from hermes_cli.config import read_raw_config
config_path = hermes_home / "config.yaml" cfg = read_raw_config()
if config_path.exists(): val = cfg.get("browser", {}).get("command_timeout")
import yaml if val is not None:
with open(config_path) as f: return max(int(val), 5) # Floor at 5s to avoid instant kills
cfg = yaml.safe_load(f) or {}
val = cfg.get("browser", {}).get("command_timeout")
if val is not None:
return max(int(val), 5) # Floor at 5s to avoid instant kills
except Exception as e: except Exception as e:
logger.debug("Could not read command_timeout from config: %s", e) logger.debug("Could not read command_timeout from config: %s", e)
return DEFAULT_COMMAND_TIMEOUT return DEFAULT_COMMAND_TIMEOUT
@ -259,23 +255,19 @@ def _get_cloud_provider() -> Optional[CloudBrowserProvider]:
_cloud_provider_resolved = True _cloud_provider_resolved = True
try: try:
hermes_home = get_hermes_home() from hermes_cli.config import read_raw_config
config_path = hermes_home / "config.yaml" cfg = read_raw_config()
if config_path.exists(): browser_cfg = cfg.get("browser", {})
import yaml provider_key = None
with open(config_path) as f: if isinstance(browser_cfg, dict) and "cloud_provider" in browser_cfg:
cfg = yaml.safe_load(f) or {} provider_key = normalize_browser_cloud_provider(
browser_cfg = cfg.get("browser", {}) browser_cfg.get("cloud_provider")
provider_key = None )
if isinstance(browser_cfg, dict) and "cloud_provider" in browser_cfg: if provider_key == "local":
provider_key = normalize_browser_cloud_provider( _cached_cloud_provider = None
browser_cfg.get("cloud_provider") return None
) if provider_key and provider_key in _PROVIDER_REGISTRY:
if provider_key == "local": _cached_cloud_provider = _PROVIDER_REGISTRY[provider_key]()
_cached_cloud_provider = None
return None
if provider_key and provider_key in _PROVIDER_REGISTRY:
_cached_cloud_provider = _PROVIDER_REGISTRY[provider_key]()
except Exception as e: except Exception as e:
logger.debug("Could not read cloud_provider from config: %s", e) logger.debug("Could not read cloud_provider from config: %s", e)
@ -326,13 +318,9 @@ def _allow_private_urls() -> bool:
_allow_private_urls_resolved = True _allow_private_urls_resolved = True
_cached_allow_private_urls = False # safe default _cached_allow_private_urls = False # safe default
try: try:
hermes_home = get_hermes_home() from hermes_cli.config import read_raw_config
config_path = hermes_home / "config.yaml" cfg = read_raw_config()
if config_path.exists(): _cached_allow_private_urls = bool(cfg.get("browser", {}).get("allow_private_urls"))
import yaml
with open(config_path) as f:
cfg = yaml.safe_load(f) or {}
_cached_allow_private_urls = bool(cfg.get("browser", {}).get("allow_private_urls"))
except Exception as e: except Exception as e:
logger.debug("Could not read allow_private_urls from config: %s", e) logger.debug("Could not read allow_private_urls from config: %s", e)
return _cached_allow_private_urls return _cached_allow_private_urls
@ -1626,14 +1614,10 @@ def _maybe_start_recording(task_id: str):
if task_id in _recording_sessions: if task_id in _recording_sessions:
return return
try: try:
from hermes_cli.config import read_raw_config
hermes_home = get_hermes_home() hermes_home = get_hermes_home()
config_path = hermes_home / "config.yaml" cfg = read_raw_config()
record_enabled = False record_enabled = cfg.get("browser", {}).get("record_sessions", False)
if config_path.exists():
import yaml
with open(config_path) as f:
cfg = yaml.safe_load(f) or {}
record_enabled = cfg.get("browser", {}).get("record_sessions", False)
if not record_enabled: if not record_enabled:
return return

View file

@ -137,40 +137,36 @@ def _load_config_files() -> List[Dict[str, str]]:
result: List[Dict[str, str]] = [] result: List[Dict[str, str]] = []
try: try:
from hermes_cli.config import read_raw_config
hermes_home = _resolve_hermes_home() hermes_home = _resolve_hermes_home()
config_path = hermes_home / "config.yaml" cfg = read_raw_config()
if config_path.exists(): cred_files = cfg.get("terminal", {}).get("credential_files")
import yaml if isinstance(cred_files, list):
hermes_home_resolved = hermes_home.resolve()
with open(config_path) as f: for item in cred_files:
cfg = yaml.safe_load(f) or {} if isinstance(item, str) and item.strip():
cred_files = cfg.get("terminal", {}).get("credential_files") rel = item.strip()
if isinstance(cred_files, list): if os.path.isabs(rel):
hermes_home_resolved = hermes_home.resolve() logger.warning(
for item in cred_files: "credential_files: rejected absolute config path %r", rel,
if isinstance(item, str) and item.strip(): )
rel = item.strip() continue
if os.path.isabs(rel): host_path = (hermes_home / rel).resolve()
logger.warning( try:
"credential_files: rejected absolute config path %r", rel, host_path.relative_to(hermes_home_resolved)
) except ValueError:
continue logger.warning(
host_path = (hermes_home / rel).resolve() "credential_files: rejected config path traversal %r "
try: "(resolves to %s, outside HERMES_HOME %s)",
host_path.relative_to(hermes_home_resolved) rel, host_path, hermes_home_resolved,
except ValueError: )
logger.warning( continue
"credential_files: rejected config path traversal %r " if host_path.is_file():
"(resolves to %s, outside HERMES_HOME %s)", container_path = f"/root/.hermes/{rel}"
rel, host_path, hermes_home_resolved, result.append({
) "host_path": str(host_path),
continue "container_path": container_path,
if host_path.is_file(): })
container_path = f"/root/.hermes/{rel}"
result.append({
"host_path": str(host_path),
"container_path": container_path,
})
except Exception as e: except Exception as e:
logger.debug("Could not read terminal.credential_files from config: %s", e) logger.debug("Could not read terminal.credential_files from config: %s", e)

View file

@ -66,18 +66,13 @@ def _load_config_passthrough() -> frozenset[str]:
result: set[str] = set() result: set[str] = set()
try: try:
from hermes_constants import get_hermes_home from hermes_cli.config import read_raw_config
config_path = get_hermes_home() / "config.yaml" cfg = read_raw_config()
if config_path.exists(): passthrough = cfg.get("terminal", {}).get("env_passthrough")
import yaml if isinstance(passthrough, list):
for item in passthrough:
with open(config_path) as f: if isinstance(item, str) and item.strip():
cfg = yaml.safe_load(f) or {} result.add(item.strip())
passthrough = cfg.get("terminal", {}).get("env_passthrough")
if isinstance(passthrough, list):
for item in passthrough:
if isinstance(item, str) and item.strip():
result.add(item.strip())
except Exception as e: except Exception as e:
logger.debug("Could not read tools.env_passthrough from config: %s", e) logger.debug("Could not read tools.env_passthrough from config: %s", e)

View file

@ -98,12 +98,8 @@ def get_stt_model_from_config() -> Optional[str]:
Silently returns ``None`` on any error (missing file, bad YAML, etc.). Silently returns ``None`` on any error (missing file, bad YAML, etc.).
""" """
try: try:
import yaml from hermes_cli.config import read_raw_config
cfg_path = get_hermes_home() / "config.yaml" return read_raw_config().get("stt", {}).get("model")
if cfg_path.exists():
with open(cfg_path) as f:
data = yaml.safe_load(f) or {}
return data.get("stt", {}).get("model")
except Exception: except Exception:
pass pass
return None return None