mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-08 03:01:47 +00:00
Serialize Hermes config access
This commit is contained in:
parent
307c85e5c1
commit
34f7297359
1 changed files with 102 additions and 90 deletions
|
|
@ -21,6 +21,7 @@ import stat
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import threading
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Any, Optional, List, Tuple
|
from typing import Dict, Any, Optional, List, Tuple
|
||||||
|
|
@ -42,6 +43,14 @@ _LOAD_CONFIG_CACHE: Dict[str, Tuple[int, int, Dict[str, Any]]] = {}
|
||||||
# _LOAD_CONFIG_CACHE but for read_raw_config() — used when callers want
|
# _LOAD_CONFIG_CACHE but for read_raw_config() — used when callers want
|
||||||
# the user's on-disk values without defaults merged in.
|
# the user's on-disk values without defaults merged in.
|
||||||
_RAW_CONFIG_CACHE: Dict[str, Tuple[int, int, Dict[str, Any]]] = {}
|
_RAW_CONFIG_CACHE: Dict[str, Tuple[int, int, Dict[str, Any]]] = {}
|
||||||
|
# Serializes all config read/write paths. libyaml's C extension is not
|
||||||
|
# thread-safe for concurrent safe_load() on the same file, and multiple
|
||||||
|
# tool threads (approval.py, browser_tool.py, setup flows) hit
|
||||||
|
# load_config / read_raw_config / save_config from different threads
|
||||||
|
# during long agent runs. RLock (not Lock) because save_config internally
|
||||||
|
# calls read_raw_config. Also covers mutation of the module-level cache
|
||||||
|
# dicts above.
|
||||||
|
_CONFIG_LOCK = threading.RLock()
|
||||||
# Env var names written to .env that aren't in OPTIONAL_ENV_VARS
|
# Env var names written to .env that aren't in OPTIONAL_ENV_VARS
|
||||||
# (managed by setup/provider flows directly).
|
# (managed by setup/provider flows directly).
|
||||||
_EXTRA_ENV_KEYS = frozenset({
|
_EXTRA_ENV_KEYS = frozenset({
|
||||||
|
|
@ -3941,6 +3950,7 @@ def read_raw_config() -> Dict[str, Any]:
|
||||||
``load_config()``. Returns a deepcopy on every call since some callers
|
``load_config()``. Returns a deepcopy on every call since some callers
|
||||||
mutate the result before passing to ``save_config()``.
|
mutate the result before passing to ``save_config()``.
|
||||||
"""
|
"""
|
||||||
|
with _CONFIG_LOCK:
|
||||||
try:
|
try:
|
||||||
config_path = get_config_path()
|
config_path = get_config_path()
|
||||||
st = config_path.stat()
|
st = config_path.stat()
|
||||||
|
|
@ -3975,6 +3985,7 @@ def load_config() -> Dict[str, Any]:
|
||||||
(which change ``HERMES_HOME`` and therefore ``get_config_path()``)
|
(which change ``HERMES_HOME`` and therefore ``get_config_path()``)
|
||||||
don't collide.
|
don't collide.
|
||||||
"""
|
"""
|
||||||
|
with _CONFIG_LOCK:
|
||||||
ensure_hermes_home()
|
ensure_hermes_home()
|
||||||
config_path = get_config_path()
|
config_path = get_config_path()
|
||||||
path_key = str(config_path)
|
path_key = str(config_path)
|
||||||
|
|
@ -4094,6 +4105,7 @@ _COMMENTED_SECTIONS = """
|
||||||
|
|
||||||
def save_config(config: Dict[str, Any]):
|
def save_config(config: Dict[str, Any]):
|
||||||
"""Save configuration to ~/.hermes/config.yaml."""
|
"""Save configuration to ~/.hermes/config.yaml."""
|
||||||
|
with _CONFIG_LOCK:
|
||||||
if is_managed():
|
if is_managed():
|
||||||
managed_error("save configuration")
|
managed_error("save configuration")
|
||||||
return
|
return
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue