Refactor configuration handling to improve user experience
- Implemented deep copy of DEFAULT_CONFIG to prevent mutations during config loading. - Enhanced user config merging process to clarify the deep merge of user values over defaults. - Added newline handling when appending environment variables to ensure proper formatting. - Updated the set_config_value function to write only user-specific configurations back to the file, avoiding overwriting default values.
This commit is contained in:
parent
e0c9d495ef
commit
dd5fe334f3
1 changed files with 28 additions and 9 deletions
|
|
@ -478,16 +478,18 @@ def migrate_config(interactive: bool = True, quiet: bool = False) -> Dict[str, A
|
||||||
|
|
||||||
def load_config() -> Dict[str, Any]:
|
def load_config() -> Dict[str, Any]:
|
||||||
"""Load configuration from ~/.hermes/config.yaml."""
|
"""Load configuration from ~/.hermes/config.yaml."""
|
||||||
|
import copy
|
||||||
config_path = get_config_path()
|
config_path = get_config_path()
|
||||||
|
|
||||||
config = DEFAULT_CONFIG.copy()
|
# Deep copy to avoid mutating DEFAULT_CONFIG
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||||
|
|
||||||
if config_path.exists():
|
if config_path.exists():
|
||||||
try:
|
try:
|
||||||
with open(config_path) as f:
|
with open(config_path) as f:
|
||||||
user_config = yaml.safe_load(f) or {}
|
user_config = yaml.safe_load(f) or {}
|
||||||
|
|
||||||
# Deep merge
|
# Deep merge user values over defaults
|
||||||
for key, value in user_config.items():
|
for key, value in user_config.items():
|
||||||
if isinstance(value, dict) and key in config and isinstance(config[key], dict):
|
if isinstance(value, dict) and key in config and isinstance(config[key], dict):
|
||||||
config[key].update(value)
|
config[key].update(value)
|
||||||
|
|
@ -544,6 +546,9 @@ def save_env_value(key: str, value: str):
|
||||||
break
|
break
|
||||||
|
|
||||||
if not found:
|
if not found:
|
||||||
|
# Ensure there's a newline at the end of the file before appending
|
||||||
|
if lines and not lines[-1].endswith("\n"):
|
||||||
|
lines[-1] += "\n"
|
||||||
lines.append(f"{key}={value}\n")
|
lines.append(f"{key}={value}\n")
|
||||||
|
|
||||||
with open(env_path, 'w') as f:
|
with open(env_path, 'w') as f:
|
||||||
|
|
@ -702,7 +707,7 @@ def set_config_value(key: str, value: str):
|
||||||
'FIRECRAWL_API_KEY', 'BROWSERBASE_API_KEY', 'BROWSERBASE_PROJECT_ID',
|
'FIRECRAWL_API_KEY', 'BROWSERBASE_API_KEY', 'BROWSERBASE_PROJECT_ID',
|
||||||
'FAL_KEY', 'TELEGRAM_BOT_TOKEN', 'DISCORD_BOT_TOKEN',
|
'FAL_KEY', 'TELEGRAM_BOT_TOKEN', 'DISCORD_BOT_TOKEN',
|
||||||
'TERMINAL_SSH_HOST', 'TERMINAL_SSH_USER', 'TERMINAL_SSH_KEY',
|
'TERMINAL_SSH_HOST', 'TERMINAL_SSH_USER', 'TERMINAL_SSH_KEY',
|
||||||
'SUDO_PASSWORD'
|
'SUDO_PASSWORD', 'SLACK_BOT_TOKEN', 'SLACK_APP_TOKEN',
|
||||||
]
|
]
|
||||||
|
|
||||||
if key.upper() in api_keys or key.upper().startswith('TERMINAL_SSH'):
|
if key.upper() in api_keys or key.upper().startswith('TERMINAL_SSH'):
|
||||||
|
|
@ -711,14 +716,23 @@ def set_config_value(key: str, value: str):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Otherwise it goes to config.yaml
|
# Otherwise it goes to config.yaml
|
||||||
config = load_config()
|
# Read the raw user config (not merged with defaults) to avoid
|
||||||
|
# dumping all default values back to the file
|
||||||
|
config_path = get_config_path()
|
||||||
|
user_config = {}
|
||||||
|
if config_path.exists():
|
||||||
|
try:
|
||||||
|
with open(config_path) as f:
|
||||||
|
user_config = yaml.safe_load(f) or {}
|
||||||
|
except Exception:
|
||||||
|
user_config = {}
|
||||||
|
|
||||||
# Handle nested keys (e.g., "terminal.backend")
|
# Handle nested keys (e.g., "tts.provider")
|
||||||
parts = key.split('.')
|
parts = key.split('.')
|
||||||
current = config
|
current = user_config
|
||||||
|
|
||||||
for part in parts[:-1]:
|
for part in parts[:-1]:
|
||||||
if part not in current:
|
if part not in current or not isinstance(current.get(part), dict):
|
||||||
current[part] = {}
|
current[part] = {}
|
||||||
current = current[part]
|
current = current[part]
|
||||||
|
|
||||||
|
|
@ -733,8 +747,13 @@ def set_config_value(key: str, value: str):
|
||||||
value = float(value)
|
value = float(value)
|
||||||
|
|
||||||
current[parts[-1]] = value
|
current[parts[-1]] = value
|
||||||
save_config(config)
|
|
||||||
print(f"✓ Set {key} = {value} in {get_config_path()}")
|
# Write only user config back (not the full merged defaults)
|
||||||
|
ensure_hermes_home()
|
||||||
|
with open(config_path, 'w') as f:
|
||||||
|
yaml.dump(user_config, f, default_flow_style=False, sort_keys=False)
|
||||||
|
|
||||||
|
print(f"✓ Set {key} = {value} in {config_path}")
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue