NousResearch/hermes-agent
Model switching routing and provider resolution bugs
Cluster 16857. Data as of
Nothing open on GitHub. Fix merged in #16897 on 28 Apr 2026. Check it covers your case.
The short answer
0open issues
0open PRs
3items grouped
- Known?
- Yes. 3 related items grouped here, 1 issue already closed.
- Fix event
- A fix was merged to main in PR #16897. Check it covers your case. No release data is tracked.
- Tracker
- The maintainers' tracker marks this
resolved, deciding PR #16897. That is separate from the fix event. - Still open
- Nothing open on GitHub.
These issues and fixes address problems where model-switching commands incorrectly route to native providers instead of configured or custom providers, leak environment/process state across sessions, and fail to honor launch-time or runtime provider overrides.
Open issues0
Open PRs0
Fixes on record
-
#16897 fix(tui): `/model` writes HERMES_TUI_PROVIDER unconditionally (#16857)
files:
tests/test_tui_gateway_server.py,tui_gateway/server.pyShow the diff
-
tests/test_tui_gateway_server.py@@ -1171,6 +1171,61 @@ def switch_model(self, **_kwargs): assert os.environ["HERMES_INFERENCE_PROVIDER"] == "anthropic" +def test_config_set_model_syncs_tui_provider_unconditionally(monkeypatch): + """Regression for #16857: /model must set HERMES_TUI_PROVIDER even when + it wasn't pre-set on launch, so a later /new (which re-runs + _resolve_startup_runtime) honours the user's explicit provider choice + instead of falling through to static-catalog detection and picking a + coincidentally-matching native provider. + """ + + class _Agent: + provider = "openrouter" + model = "old/model" + base_url = "" + api_key = "sk-or" + + def switch_model(self, **_kwargs): + return None + + result = types.SimpleNamespace( + success=True, + new_model="deepseek-v4-pro", + target_provider="custom:xuanji", + api_key="[redacted:secret-assignment]", + base_url="https://xuanji.example/v1", + api_mode="chat_completions", + warning_message="", + ) + + server._sessions["sid"] = _session(agent=_Agent()) + monkeypatch.delenv("HERMES_TUI_PROVIDER", raising=False) + monkeypatch.delenv("HERMES_INFERENCE_PROVIDER", raising=False) + monkeypatch.setattr( + "hermes_cli.model_switch.switch_model", lambda **_kwargs: result + ) + monkeypatch.setattr(server, "_restart_slash_worker", lambda session: None) + monkeypatch.setattr(server, "_emit", lambda *args, **kwargs: None) + + server.handle_request( + { + "id": "1", + "method": "config.set", + "params": { + "session_id": "sid", + "key": "model", + "value": "deepseek-v4-pro --provider custom:xuanji", + }, + } + ) + + # Both env vars must reflect the user's choice. HERMES_TUI_PROVIDER is + # the canonical explicit-this-process carrier consumed by + # _resolve_startup_runtime() on /new. + assert os.environ["HERMES_TUI_PROVIDER"] == "custom:xuanji" + assert os.environ["HERMES_INFERENCE_PROVIDER"] == "custom:xuanji" + + def test_config_set_model_syncs_tui_provider_env(monkeypatch): class Agent: model = "gpt-5.3-codex" -
tui_gateway/server.py@@ -843,14 +843,19 @@ def _apply_model_switch(sid: str, session: dict, raw_input: str) -> dict: os.environ["HERMES_MODEL"] = result.new_model os.environ["HERMES_INFERENCE_MODEL"] = result.new_model - # Keep the process-level provider env var in sync with the user's explicit - # choice so any ambient re-resolution (credential pool refresh, compressor - # rebuild, aux clients) resolves to the new provider instead of the - # original one persisted in config or env. + # Keep the process-level provider env vars in sync with the user's + # explicit choice so any ambient re-resolution (credential pool refresh, + # compressor rebuild, aux clients) and startup re-resolution on /new + # both pick up the new provider instead of the original one persisted + # in config or env. + # + # HERMES_TUI_PROVIDER is the canonical "explicit-this-process" carrier + # consumed by _resolve_startup_runtime() — set it unconditionally on + # /model so /new can't fall through to static-catalog detection and + # pick a coincidentally-matching native provider (fixes #16857). if result.target_provider: os.environ["HERMES_INFERENCE_PROVIDER"] = result.target_provider - if os.environ.get("HERMES_TUI_PROVIDER"): - os.environ["HERMES_TUI_PROVIDER"] = result.target_provider + os.environ["HERMES_TUI_PROVIDER"] = result.target_provider if persist_global: _persist_model_switch(result) return {"value": result.new_model, "warning": result.warning_message or ""}
-
1 PR closed without merging
From the close comments: superseded by another PR 1
-
#16873 fix(gateway): honour HERMES_INFERENCE_PROVIDER in _resolve_startup_runtime (#16857) · superseded by another PR →
#16897,#16857,#15755
Closed issues · 1
- Closed#16857TUI: /new after /model switch to custom provider model fails with 'no API key' when model name exists in native provider catalog
How this cluster was grouped
-
Link evidence (
structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference. -
Pairwise link density
0.67: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36.1.00means every pair is linked.
Pick up a Lab task
Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.
Open the LabAt a glance
- Merged PRs
- #16897
- Closed issues
- 1
- Attempts
- 1 PR closed without merging
- Fix link checked
- 28 Apr 2026. This confirmation is old and may be out of date (a revert or reopen would not have invalidated it here); re-verify.