Compare commits

...

3 Commits

Author SHA1 Message Date
5c5c9e2723 cleanup: remove dead server config methods from config_manager
get_server_config() and set_server_config() in ConfigManager had zero
callers — every part of the codebase already uses the server_manager
singleton. Removing them eliminates the risk of a stale write that
bypasses the in-memory cache in ServerManager.

server_manager is now the sole owner of servers_config.json.
2026-04-08 15:47:36 +03:00
b4e48ce375 fix: /config/set now syncs all runtime-relevant globals
Previously only 4 of 5+ settings were synced to globals when set via
the generic /config/set endpoint. Added:
- memory.use_cheshire_cat -> globals.USE_CHESHIRE_CAT
- runtime.mood.dm_mood -> globals.DM_MOOD + DM_MOOD_DESCRIPTION
- Uses same _GLOBALS_SYNC mapping pattern as restore_runtime_settings
2026-04-08 15:05:25 +03:00
7c9cf0d8b4 fix: /config/reset now resets live globals to defaults
reset_to_defaults() previously only cleared the runtime_config dict and
saved config_runtime.yaml, but never touched the actual globals that
control runtime behavior. After a reset, LANGUAGE_MODE, AUTONOMOUS_DEBUG,
VOICE_DEBUG_MODE, USE_CHESHIRE_CAT, PREFER_AMD_GPU, and DM_MOOD all kept
their current in-memory values until the next restart.

Now reset_to_defaults() also resets the corresponding globals to their
default values from CONFIG (the static config loaded from config.yaml).
Both full reset and single-key reset are supported. The default values
come from the Pydantic AppConfig schema, ensuring consistency.

Tested: set non-default values, full reset -> all back to defaults,
single-key reset -> only that key back to default, runtime_state property
reflects the reset immediately.
2026-04-08 14:58:29 +03:00
2 changed files with 60 additions and 51 deletions

View File

@@ -2978,15 +2978,27 @@ async def set_config_value(request: Request):
from config_manager import config_manager from config_manager import config_manager
config_manager.set(key_path, value, persist=persist) config_manager.set(key_path, value, persist=persist)
# Update globals if needed # ── Sync globals for every runtime-relevant key path ──
if key_path == "discord.language_mode": _GLOBALS_SYNC = {
globals.LANGUAGE_MODE = value "discord.language_mode": ("LANGUAGE_MODE", str),
elif key_path == "autonomous.debug_mode": "autonomous.debug_mode": ("AUTONOMOUS_DEBUG", bool),
globals.AUTONOMOUS_DEBUG = value "voice.debug_mode": ("VOICE_DEBUG_MODE", bool),
elif key_path == "voice.debug_mode": "memory.use_cheshire_cat": ("USE_CHESHIRE_CAT", bool),
globals.VOICE_DEBUG_MODE = value "gpu.prefer_amd": ("PREFER_AMD_GPU", bool),
elif key_path == "gpu.prefer_amd": }
globals.PREFER_AMD_GPU = value
if key_path in _GLOBALS_SYNC:
attr, converter = _GLOBALS_SYNC[key_path]
setattr(globals, attr, converter(value))
elif key_path == "runtime.mood.dm_mood":
# DM mood needs description loaded alongside
if isinstance(value, str) and value in getattr(globals, "AVAILABLE_MOODS", []):
globals.DM_MOOD = value
try:
from utils.moods import load_mood_description
globals.DM_MOOD_DESCRIPTION = load_mood_description(value)
except Exception:
globals.DM_MOOD_DESCRIPTION = f"I'm feeling {value} today."
return { return {
"success": True, "success": True,

View File

@@ -225,9 +225,16 @@ class ConfigManager:
""" """
Reset configuration to defaults. Reset configuration to defaults.
Clears runtime overrides from config_runtime.yaml AND resets the
corresponding globals to their default values so the change takes
effect immediately without a restart.
Args: Args:
key_path: Specific key to reset, or None to reset all runtime config key_path: Specific key to reset, or None to reset all runtime config
""" """
import globals as g
from config import CONFIG
if key_path: if key_path:
# Remove specific key from runtime config # Remove specific key from runtime config
self._remove_nested_key(self.runtime_config, key_path) self._remove_nested_key(self.runtime_config, key_path)
@@ -239,6 +246,38 @@ class ConfigManager:
self.save_runtime_config() self.save_runtime_config()
# ---- Reset live globals to match defaults ----
# Map: config_runtime key path -> (globals attr, default from CONFIG)
_DEFAULTS_MAP = {
"discord.language_mode": ("LANGUAGE_MODE", CONFIG.discord.language_mode),
"autonomous.debug_mode": ("AUTONOMOUS_DEBUG", CONFIG.autonomous.debug_mode),
"voice.debug_mode": ("VOICE_DEBUG_MODE", CONFIG.voice.debug_mode),
"memory.use_cheshire_cat": ("USE_CHESHIRE_CAT", CONFIG.cheshire_cat.enabled),
"gpu.prefer_amd": ("PREFER_AMD_GPU", CONFIG.gpu.prefer_amd),
}
reset_items = []
if key_path:
# Reset only the specific global
if key_path in _DEFAULTS_MAP:
attr, default = _DEFAULTS_MAP[key_path]
setattr(g, attr, default)
reset_items.append(f"{attr}={default}")
else:
# Reset all globals to defaults
for kp, (attr, default) in _DEFAULTS_MAP.items():
setattr(g, attr, default)
reset_items.append(f"{attr}={default}")
# Also reset DM mood to neutral
g.DM_MOOD = "neutral"
g.DM_MOOD_DESCRIPTION = "I'm feeling neutral and balanced today."
reset_items.append("DM_MOOD=neutral")
if reset_items:
logger.info(f"🔄 Reset {len(reset_items)} globals: {', '.join(reset_items)}")
def _remove_nested_key(self, config: Dict, key_path: str): def _remove_nested_key(self, config: Dict, key_path: str):
"""Remove nested key from config.""" """Remove nested key from config."""
keys = key_path.split(".") keys = key_path.split(".")
@@ -282,48 +321,6 @@ class ConfigManager:
self._current_gpu = value self._current_gpu = value
logger.debug(f"📊 State: {key} = {value}") logger.debug(f"📊 State: {key} = {value}")
# ========== Server Configuration ==========
def get_server_config(self, guild_id: int) -> Dict:
"""Get configuration for a specific server."""
server_config_file = self.memory_dir / "servers_config.json"
try:
if server_config_file.exists():
with open(server_config_file, "r") as f:
all_servers = json.load(f)
return all_servers.get(str(guild_id), {})
except Exception as e:
logger.error(f"❌ Failed to load server config: {e}")
return {}
def set_server_config(self, guild_id: int, config: Dict):
"""Set configuration for a specific server."""
server_config_file = self.memory_dir / "servers_config.json"
try:
# Load existing config
all_servers = {}
if server_config_file.exists():
with open(server_config_file, "r") as f:
all_servers = json.load(f)
# Update server config
all_servers[str(guild_id)] = {
**all_servers.get(str(guild_id), {}),
**config,
"last_updated": datetime.now().isoformat()
}
# Save
with open(server_config_file, "w") as f:
json.dump(all_servers, f, indent=2)
logger.info(f"💾 Saved server config for {guild_id}")
except Exception as e:
logger.error(f"❌ Failed to save server config: {e}")
# ========== GPU State ========== # ========== GPU State ==========
def get_gpu(self) -> str: def get_gpu(self) -> str: