fix(#5619): reload model payloads on profile switch
This commit is contained in:
parent
2f815f040c
commit
1124fd882a
2 changed files with 76 additions and 4 deletions
|
|
@ -5759,10 +5759,9 @@ def get_available_models(*, prefer_cache: bool = False, force_refresh: bool = Fa
|
|||
except OSError:
|
||||
_current_path = _get_config_path()
|
||||
_current_mtime = 0.0
|
||||
if (
|
||||
(_current_mtime != _cfg_mtime or _current_path != _cfg_path)
|
||||
and not _cfg_has_in_memory_overrides()
|
||||
):
|
||||
path_changed = _current_path != _cfg_path
|
||||
mtime_stale = _current_mtime != _cfg_mtime
|
||||
if path_changed or (mtime_stale and not _cfg_has_in_memory_overrides()):
|
||||
reload_config_if_stale()
|
||||
# ── COLD PATH helper ─────────────────────────────────────────────────────
|
||||
# Extracted so it runs inside _available_models_cache_lock (RLock) to
|
||||
|
|
|
|||
|
|
@ -591,6 +591,79 @@ def test_get_config_reloads_when_request_profile_changes_even_with_rebound_cfg_o
|
|||
config.cfg = orig_cfg
|
||||
|
||||
|
||||
def test_get_available_models_reloads_when_request_profile_changes_even_with_rebound_cfg_override(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
"""The models payload must follow the new profile even when cfg was rebound."""
|
||||
monkeypatch.delenv("HERMES_CONFIG_PATH", raising=False)
|
||||
import api.config as config
|
||||
import api.profiles as profiles
|
||||
|
||||
default_home = tmp_path / ".hermes"
|
||||
work_home = default_home / "profiles" / "work"
|
||||
work_home.mkdir(parents=True)
|
||||
default_home.mkdir(exist_ok=True)
|
||||
(default_home / "config.yaml").write_text(
|
||||
"model:\n provider: openai-codex\n default: gpt-5.5\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(work_home / "config.yaml").write_text(
|
||||
"model:\n provider: openrouter\n default: google/gemini-3-flash-preview\n"
|
||||
"custom_providers:\n llamacpp:\n api_key: work-key\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
same_mtime = 1_700_000_000
|
||||
os.utime(default_home / "config.yaml", (same_mtime, same_mtime))
|
||||
os.utime(work_home / "config.yaml", (same_mtime, same_mtime))
|
||||
|
||||
monkeypatch.setattr(
|
||||
config,
|
||||
"_get_config_path",
|
||||
lambda: profiles.get_active_hermes_home() / "config.yaml",
|
||||
)
|
||||
monkeypatch.setattr(config, "_LIVE_REBUILD_BUDGET_SECONDS", 0.0, raising=False)
|
||||
|
||||
orig_default_home = profiles._DEFAULT_HERMES_HOME
|
||||
orig_active = profiles._active_profile
|
||||
orig_cache = dict(config._cfg_cache)
|
||||
orig_mtime = config._cfg_mtime
|
||||
orig_path = getattr(config, "_cfg_path", None)
|
||||
orig_fingerprint = getattr(config, "_cfg_fingerprint", None)
|
||||
orig_cfg = config.cfg
|
||||
profiles._tls.profile = None
|
||||
try:
|
||||
profiles._DEFAULT_HERMES_HOME = default_home
|
||||
profiles._active_profile = "default"
|
||||
config.reload_config()
|
||||
config.invalidate_models_cache()
|
||||
monkeypatch.setattr(
|
||||
config,
|
||||
"cfg",
|
||||
{"model": {"provider": "stale-override", "default": "old-model"}},
|
||||
raising=False,
|
||||
)
|
||||
|
||||
profiles.set_request_profile("work")
|
||||
assert config._get_config_path() == work_home / "config.yaml"
|
||||
result = config.get_available_models()
|
||||
assert result["active_provider"] == "openrouter"
|
||||
assert result["default_model"] == "google/gemini-3-flash-preview"
|
||||
assert config.cfg is config._cfg_cache
|
||||
finally:
|
||||
profiles.clear_request_profile()
|
||||
profiles._DEFAULT_HERMES_HOME = orig_default_home
|
||||
profiles._active_profile = orig_active
|
||||
config._cfg_cache.clear()
|
||||
config._cfg_cache.update(orig_cache)
|
||||
config._cfg_mtime = orig_mtime
|
||||
if hasattr(config, "_cfg_path"):
|
||||
config._cfg_path = orig_path
|
||||
if hasattr(config, "_cfg_fingerprint"):
|
||||
config._cfg_fingerprint = orig_fingerprint
|
||||
config.cfg = orig_cfg
|
||||
config.invalidate_models_cache()
|
||||
|
||||
|
||||
def test_chat_start_retags_empty_session_to_request_profile(monkeypatch, tmp_path):
|
||||
"""An empty session created under profile A can be sent under profile B after a switch."""
|
||||
import api.routes as routes
|
||||
|
|
|
|||
Loading…
Reference in a new issue