mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-22 16:25:58 +00:00
fix(web): clear stale api-alias credential on provider switch in main-model assignment
c253b0738 added clear_model_endpoint_credentials() to scrub an old endpoint's
inline secret (api_key, the legacy `api` alias, api_mode) when the web UI
switches the main model to a different provider. But _apply_main_model_assignment
gates the key-scrub path on model_cfg["api_key"] being truthy, so when the stale
secret lives only under the legacy `api` alias (no api_key), a provider switch
never clears it — the secret survives in config.yaml.
model.api is a live credential read path (_resolve_openrouter_runtime reads
`for k in ("api_key", "api")`), so the old endpoint's key contaminates a later
custom resolution — the exact harm clear_model_endpoint_credentials documents.
The sibling persistence sites (the gateway model-picker paths and the aux-slot
path) call the helper unconditionally on a non-custom switch and already scrub
`api`; only this caller had the api_key-only gate.
Widen the guard to fire on either field. The same-provider re-pick and
explicit-new-key paths are unchanged. Adds the api-alias case to the assignment
test (it fails without the fix).
This commit is contained in:
parent
977884e6cd
commit
28028cce55
2 changed files with 18 additions and 1 deletions
|
|
@ -1346,7 +1346,12 @@ def _apply_main_model_assignment(
|
|||
if api_key.strip():
|
||||
model_cfg["api_key"] = api_key.strip()
|
||||
model_cfg.pop("api", None)
|
||||
elif model_cfg.get("api_key") and new_provider != prev_provider:
|
||||
elif (model_cfg.get("api_key") or model_cfg.get("api")) and new_provider != prev_provider:
|
||||
# A stale endpoint secret can live under the legacy ``api`` alias with
|
||||
# no ``api_key`` (the resolver still reads ``model.api`` as a key), so
|
||||
# the switch-clears-the-key path must trigger on either field — else the
|
||||
# old endpoint's secret survives in config.yaml and contaminates a later
|
||||
# custom resolution. clear_model_endpoint_credentials scrubs both.
|
||||
clear_model_endpoint_credentials(model_cfg, clear_api_mode=False)
|
||||
if new_provider != prev_provider:
|
||||
clear_model_endpoint_credentials(model_cfg, clear_api_key=False)
|
||||
|
|
|
|||
|
|
@ -3989,6 +3989,18 @@ class TestWebServerEndpoints:
|
|||
assert "api_key" not in out
|
||||
assert "api_mode" not in out
|
||||
|
||||
# switching providers when the stale secret lives under the legacy
|
||||
# ``api`` alias only (no api_key) → it must be cleared too. The resolver
|
||||
# reads ``model.api`` as a key, so leaving it behind keeps a secret in
|
||||
# config.yaml that contaminates the next custom resolution.
|
||||
out = _apply_main_model_assignment(
|
||||
{"provider": "custom", "api": "sk-legacy-stale", "base_url": "http://endpoint-a/v1"},
|
||||
"openrouter",
|
||||
"m",
|
||||
)
|
||||
assert "api" not in out
|
||||
assert "api_key" not in out
|
||||
|
||||
def test_parse_model_ids_handles_openai_and_bare_shapes(self):
|
||||
"""Model discovery must tolerate the common /v1/models shapes and
|
||||
never raise (so a slightly non-standard local endpoint still works)."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue