Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions agent/agent_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ def init_agent(
# sessions with >5-minute pauses between turns (#14971).
agent._cache_ttl = "5m"
try:
from hermes_cli.config import load_config as _load_pc_cfg
from hermes_cli.config import load_config_readonly as _load_pc_cfg

_pc_cfg = _load_pc_cfg().get("prompt_caching", {}) or {}
_ttl = _pc_cfg.get("cache_ttl", "5m")
Expand Down Expand Up @@ -776,7 +776,7 @@ def _moa_reference_relay(event: str, **kwargs: Any) -> None:
# Guardrail config — read from config.yaml at init time.
agent._bedrock_guardrail_config = None
try:
from hermes_cli.config import load_config as _load_br_cfg
from hermes_cli.config import load_config_readonly as _load_br_cfg
_gr = _load_br_cfg().get("bedrock", {}).get("guardrail", {})
if _gr.get("guardrail_identifier") and _gr.get("guardrail_version"):
agent._bedrock_guardrail_config = {
Expand Down Expand Up @@ -1124,7 +1124,7 @@ def _moa_reference_relay(event: str, **kwargs: Any) -> None:
# reads the JSON files directly. See run_agent._save_session_log.
agent._session_json_enabled = False
try:
from hermes_cli.config import load_config as _load_sess_cfg
from hermes_cli.config import load_config_readonly as _load_sess_cfg
_sess_cfg = (_load_sess_cfg().get("sessions") or {})
agent._session_json_enabled = bool(_sess_cfg.get("write_json_snapshots", False))
except Exception:
Expand Down Expand Up @@ -1179,7 +1179,7 @@ def _moa_reference_relay(event: str, **kwargs: Any) -> None:

# Load config once for memory, skills, and compression sections
try:
from hermes_cli.config import load_config as _load_agent_config
from hermes_cli.config import load_config_readonly as _load_agent_config
_agent_cfg = _load_agent_config()
except Exception:
_agent_cfg = {}
Expand Down
4 changes: 2 additions & 2 deletions agent/agent_runtime_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1718,8 +1718,8 @@ def switch_model(agent, new_model, new_provider, api_key='', base_url='', api_mo
# custom provider mid-session (closes #15779).
_sm_custom_providers = None
try:
from hermes_cli.config import load_config, get_compatible_custom_providers
_sm_cfg = load_config()
from hermes_cli.config import load_config_readonly, get_compatible_custom_providers
_sm_cfg = load_config_readonly()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

load_config_readonly() returns the shared cached dict, but this value is passed to get_compatible_custom_providers(). On current main, its normalizer writes alias keys into provider-entry dicts (hermes_cli/config.py:4699-4700, :4714-4722), so this path can corrupt the config cache. Please make that normalizer/caller non-mutating before using the readonly loader here.

_sm_custom_providers = get_compatible_custom_providers(_sm_cfg)
except Exception:
_sm_custom_providers = None
Expand Down
42 changes: 21 additions & 21 deletions agent/auxiliary_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,8 +425,8 @@ def _apply_user_default_headers(headers: dict | None) -> dict | None:
when nothing is configured. No allocation when there are no overrides.
"""
try:
from hermes_cli.config import cfg_get, load_config
user_headers = cfg_get(load_config(), "model", "default_headers")
from hermes_cli.config import cfg_get, load_config_readonly
user_headers = cfg_get(load_config_readonly(), "model", "default_headers")
except Exception:
return headers
if not isinstance(user_headers, dict) or not user_headers:
Expand All @@ -452,15 +452,15 @@ def build_or_headers(or_config: dict | None = None) -> dict:
Overrides ``openrouter.response_cache_ttl`` in config.yaml.

*or_config* is the ``openrouter`` section from config.yaml. When *None*,
falls back to reading config from disk via ``load_config()``.
falls back to reading config from disk via ``load_config_readonly()``.
"""
headers = dict(_OR_HEADERS_BASE)

# Resolve config from disk if not provided.
if or_config is None:
try:
from hermes_cli.config import load_config
or_config = load_config().get("openrouter", {})
from hermes_cli.config import load_config_readonly
or_config = load_config_readonly().get("openrouter", {})
except Exception:
or_config = {}

Expand Down Expand Up @@ -1859,8 +1859,8 @@ def _read_main_model() -> str:
if isinstance(override, str) and override.strip():
return override.strip()
try:
from hermes_cli.config import load_config
cfg = load_config()
from hermes_cli.config import load_config_readonly
cfg = load_config_readonly()
model_cfg = cfg.get("model", {})
if isinstance(model_cfg, str) and model_cfg.strip():
return model_cfg.strip()
Expand All @@ -1886,8 +1886,8 @@ def _read_main_provider() -> str:
if isinstance(override, str) and override.strip():
return override.strip().lower()
try:
from hermes_cli.config import load_config
cfg = load_config()
from hermes_cli.config import load_config_readonly
cfg = load_config_readonly()
model_cfg = cfg.get("model", {})
if isinstance(model_cfg, dict):
provider = model_cfg.get("provider", "")
Expand Down Expand Up @@ -2198,12 +2198,12 @@ def _try_azure_foundry(
try:
from hermes_cli.runtime_provider import _resolve_azure_foundry_runtime
from hermes_cli.auth import AuthError
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly
except ImportError:
return None, None

try:
cfg = load_config()
cfg = load_config_readonly()
model_cfg = cfg.get("model") if isinstance(cfg, dict) else {}
if not isinstance(model_cfg, dict):
model_cfg = {}
Expand Down Expand Up @@ -2309,8 +2309,8 @@ def _try_anthropic(explicit_api_key: str = None) -> Tuple[Optional[Any], Optiona
# see issue #52608.
base_url = _pool_runtime_base_url(entry, _ANTHROPIC_DEFAULT_BASE_URL) if pool_present else _ANTHROPIC_DEFAULT_BASE_URL
try:
from hermes_cli.config import load_config
cfg = load_config()
from hermes_cli.config import load_config_readonly
cfg = load_config_readonly()
model_cfg = cfg.get("model")
if isinstance(model_cfg, dict):
cfg_provider = str(model_cfg.get("provider") or "").strip().lower()
Expand Down Expand Up @@ -3489,10 +3489,10 @@ def _try_main_fallback_chain(
participate in the same order as the main agent.
"""
try:
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly
from hermes_cli.fallback_config import get_fallback_chain

chain = get_fallback_chain(load_config())
chain = get_fallback_chain(load_config_readonly())
except Exception as exc:
logger.debug("Auxiliary %s: could not load main fallback chain: %s", task or "call", exc)
return None, None, ""
Expand Down Expand Up @@ -3654,10 +3654,10 @@ def _resolve_auto(
# with that real provider+model. Mirrors the MoA context-length resolution.
if main_provider == "moa":
try:
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly
from hermes_cli.moa_config import resolve_moa_preset

_preset = resolve_moa_preset(load_config().get("moa") or {}, main_model)
_preset = resolve_moa_preset(load_config_readonly().get("moa") or {}, main_model)
_agg = _preset.get("aggregator") or {}
_agg_provider = str(_agg.get("provider") or "").strip()
_agg_model = str(_agg.get("model") or "").strip()
Expand Down Expand Up @@ -4560,11 +4560,11 @@ def _main_model_supports_vision(provider: str, model: Optional[str]) -> bool:
"""
try:
from agent.image_routing import _lookup_supports_vision
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly
except ImportError:
return True
try:
supports = _lookup_supports_vision(provider, model, load_config())
supports = _lookup_supports_vision(provider, model, load_config_readonly())
except Exception: # pragma: no cover - defensive
return True
if supports is None:
Expand Down Expand Up @@ -5281,8 +5281,8 @@ def _get_auxiliary_task_config(task: str) -> Dict[str, Any]:
if not task:
return {}
try:
from hermes_cli.config import load_config
config = load_config()
from hermes_cli.config import load_config_readonly
config = load_config_readonly()
except ImportError:
return {}
aux = config.get("auxiliary", {}) if isinstance(config, dict) else {}
Expand Down
4 changes: 2 additions & 2 deletions agent/background_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ def _resolve_review_runtime(agent: Any) -> Dict[str, Any]:
"routed": False,
}
try:
from hermes_cli.config import load_config
cfg = load_config()
from hermes_cli.config import load_config_readonly
cfg = load_config_readonly()
except Exception:
return parent
aux = cfg.get("auxiliary", {}) if isinstance(cfg.get("auxiliary"), dict) else {}
Expand Down
4 changes: 2 additions & 2 deletions agent/coding_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,9 +337,9 @@ def _coding_mode(config: Optional[dict[str, Any]]) -> str:
"""Return the normalized ``agent.coding_context`` mode (auto/focus/on/off)."""
if config is None:
try:
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly

config = load_config()
config = load_config_readonly()
except Exception:
config = {}
raw = ((config or {}).get("agent", {}) or {}).get("coding_context", "auto")
Expand Down
4 changes: 2 additions & 2 deletions agent/credential_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@
def _load_config_safe() -> Optional[dict]:
"""Load config.yaml, returning None on any error."""
try:
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly

return load_config()
return load_config_readonly()
except Exception:
return None

Expand Down
8 changes: 4 additions & 4 deletions agent/curator.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ def is_paused() -> bool:
def _load_config() -> Dict[str, Any]:
"""Read curator.* config from ~/.hermes/config.yaml. Tolerates missing file."""
try:
from hermes_cli.config import load_config
cfg = load_config()
from hermes_cli.config import load_config_readonly
cfg = load_config_readonly()
except Exception as e:
logger.debug("Failed to load config for curator: %s", e)
return {}
Expand Down Expand Up @@ -1852,9 +1852,9 @@ def _run_llm_review(prompt: str) -> Dict[str, Any]:
_resolved_provider = None
_model_name = ""
try:
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly
from hermes_cli.runtime_provider import resolve_runtime_provider
_cfg = load_config()
_cfg = load_config_readonly()
_binding = _resolve_review_runtime(_cfg)
_provider, _model_name = _binding.provider, _binding.model
_rp = resolve_runtime_provider(
Expand Down
4 changes: 2 additions & 2 deletions agent/curator_backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ def _utc_id(now: Optional[datetime] = None) -> str:

def _load_config() -> Dict[str, Any]:
try:
from hermes_cli.config import load_config
cfg = load_config()
from hermes_cli.config import load_config_readonly
cfg = load_config_readonly()
except Exception as e:
logger.debug("Failed to load config for curator backup: %s", e)
return {}
Expand Down
4 changes: 2 additions & 2 deletions agent/i18n.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,8 @@ def _config_language_cached() -> str | None:
(e.g. after the setup wizard).
"""
try:
from hermes_cli.config import load_config
cfg = load_config()
from hermes_cli.config import load_config_readonly
cfg = load_config_readonly()
lang = (cfg.get("display") or {}).get("language")
if lang:
return _normalize_lang(lang)
Expand Down
4 changes: 2 additions & 2 deletions agent/image_gen_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ def get_active_provider() -> Optional[ImageGenProvider]:
"""
configured: Optional[str] = None
try:
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly

cfg = load_config()
cfg = load_config_readonly()
section = cfg.get("image_gen") if isinstance(cfg, dict) else None
if isinstance(section, dict):
raw = section.get("provider")
Expand Down
4 changes: 2 additions & 2 deletions agent/lsp/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,8 @@ def create_from_config(cls) -> Optional["LSPService"]:
itself returns ``is_active()`` False when LSP is disabled.
"""
try:
from hermes_cli.config import load_config
cfg = load_config()
from hermes_cli.config import load_config_readonly
cfg = load_config_readonly()
except Exception as e: # noqa: BLE001
logger.debug("LSP config load failed: %s", e)
return None
Expand Down
4 changes: 2 additions & 2 deletions agent/moa_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,10 +466,10 @@ def _emit(self, event: str, **kwargs: Any) -> None:
logger.debug("MoA reference_callback failed for %s: %s", event, exc)

def create(self, **api_kwargs: Any) -> Any:
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly
from hermes_cli.moa_config import resolve_moa_preset

preset = resolve_moa_preset(load_config().get("moa") or {}, self.preset_name)
preset = resolve_moa_preset(load_config_readonly().get("moa") or {}, self.preset_name)
messages = list(api_kwargs.get("messages") or [])
reference_models = preset.get("reference_models") or []
aggregator = preset.get("aggregator") or {}
Expand Down
4 changes: 2 additions & 2 deletions agent/model_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -1716,11 +1716,11 @@ def get_model_context_length(
# acting context, so they're ignored here.
if (provider or "").strip().lower() == "moa":
try:
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly
from hermes_cli.moa_config import resolve_moa_preset
from hermes_cli.runtime_provider import resolve_runtime_provider

preset = resolve_moa_preset(load_config().get("moa") or {}, model)
preset = resolve_moa_preset(load_config_readonly().get("moa") or {}, model)
agg = preset.get("aggregator") or {}
agg_provider = str(agg.get("provider") or "").strip()
agg_model = str(agg.get("model") or "").strip()
Expand Down
4 changes: 2 additions & 2 deletions agent/plugin_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,8 @@ def _resolve_trust_policy(plugin_id: str) -> _TrustPolicy:
return _TrustPolicy(plugin_id="")

try:
from hermes_cli.config import load_config
config = load_config() or {}
from hermes_cli.config import load_config_readonly
config = load_config_readonly() or {}
except Exception: # pragma: no cover — config IO failure
return _TrustPolicy(plugin_id=plugin_id)

Expand Down
8 changes: 4 additions & 4 deletions agent/prompt_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -1156,10 +1156,10 @@ def build_environment_hints() -> str:
extra = (os.getenv("HERMES_ENVIRONMENT_HINT") or "").strip()
if not extra:
try:
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly

extra = str(
(load_config().get("agent", {}) or {}).get("environment_hint", "")
(load_config_readonly().get("agent", {}) or {}).get("environment_hint", "")
).strip()
except Exception as e:
logger.debug("Could not read agent.environment_hint from config: %s", e)
Expand Down Expand Up @@ -1210,9 +1210,9 @@ def _get_context_file_max_chars(context_length: Optional[int] = None) -> int:
3. ``CONTEXT_FILE_MAX_CHARS`` (20K) as the upstream-compatible fallback.
"""
try:
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly

val = load_config().get("context_file_max_chars")
val = load_config_readonly().get("context_file_max_chars")
if isinstance(val, (int, float)) and val > 0:
return int(val)
except Exception as e:
Expand Down
4 changes: 2 additions & 2 deletions agent/skill_preprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
def load_skills_config() -> dict:
"""Load the ``skills`` section of config.yaml (best-effort)."""
try:
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly

cfg = load_config() or {}
cfg = load_config_readonly() or {}
skills_cfg = cfg.get("skills")
if isinstance(skills_cfg, dict):
return skills_cfg
Expand Down
4 changes: 2 additions & 2 deletions agent/title_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@
def _title_language() -> str:
"""Return configured title language, or empty string to match the user."""
try:
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly

return str(
((load_config() or {}).get("auxiliary") or {})
((load_config_readonly() or {}).get("auxiliary") or {})
.get("title_generation", {})
.get("language", "")
).strip()
Expand Down
4 changes: 2 additions & 2 deletions agent/verification_stop.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,9 @@ def verify_on_stop_enabled(config: dict[str, Any] | None = None) -> bool:
return env.strip().lower() not in {"0", "false", "no", "off"}
if config is None:
try:
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly

config = load_config()
config = load_config_readonly()
except Exception:
config = {}
agent_cfg = (config or {}).get("agent") if isinstance(config, dict) else None
Expand Down
4 changes: 2 additions & 2 deletions agent/video_gen_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ def get_active_provider() -> Optional[VideoGenProvider]:
"""
configured: Optional[str] = None
try:
from hermes_cli.config import load_config
from hermes_cli.config import load_config_readonly

cfg = load_config()
cfg = load_config_readonly()
section = cfg.get("video_gen") if isinstance(cfg, dict) else None
if isinstance(section, dict):
raw = section.get("provider")
Expand Down
Loading