mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-15 09:21:36 +00:00
fix(gateway): don't restore a bare billing provider as the resumed session's provider
`_stored_session_runtime_overrides` restored the session provider from `billing_provider` when `model_config` had no explicit provider. For a `custom:<name>` endpoint that only ran normal turns (no `/model` switch), the persisted `billing_provider` is the bare billing bucket `"custom"`, which `agent_init` treats as non-routable, so `session.resume` failed with "No LLM provider configured" even though new chats and CLI `--resume` work. Only restore an explicit `model_config.provider`; skip a bare billing bucket (`auto`/`openrouter`/`custom`) so resume falls back to the configured default, matching the CLI path. Fixes #44022
This commit is contained in:
parent
cb125c2b3f
commit
e256f4aae4
2 changed files with 45 additions and 5 deletions
|
|
@ -971,6 +971,35 @@ def test_session_resume_passes_stored_runtime_to_agent(monkeypatch):
|
|||
assert server._sessions[runtime_sid]["model_override"] == captured["model_override"]
|
||||
|
||||
|
||||
def test_stored_session_runtime_overrides_skips_bare_billing_provider():
|
||||
"""A bare billing bucket ("custom"/"auto"/"openrouter") must not be restored as the
|
||||
provider identity on resume. A custom endpoint that never used `/model` persists only
|
||||
`billing_provider="custom"`; restoring that broke `session.resume` with "No LLM provider
|
||||
configured" (agent_init treats it as non-routable). A real provider, or an explicit
|
||||
`model_config.provider`, is still restored.
|
||||
"""
|
||||
# Bare "custom" bucket, no explicit model_config.provider: no provider override restored.
|
||||
ov = server._stored_session_runtime_overrides({"model": "my-model", "billing_provider": "custom"})
|
||||
assert "provider_override" not in ov
|
||||
assert ov["model_override"]["provider"] is None
|
||||
|
||||
for bare in ("auto", "openrouter", "custom"):
|
||||
ov = server._stored_session_runtime_overrides({"model": "m", "billing_provider": bare})
|
||||
assert "provider_override" not in ov
|
||||
|
||||
# A real provider in billing_provider is still restored.
|
||||
ov = server._stored_session_runtime_overrides({"model": "m", "billing_provider": "anthropic"})
|
||||
assert ov["provider_override"] == "anthropic"
|
||||
assert ov["model_override"]["provider"] == "anthropic"
|
||||
|
||||
# An explicit routable provider in model_config wins over the bare billing bucket.
|
||||
ov = server._stored_session_runtime_overrides(
|
||||
{"model": "m", "billing_provider": "custom", "model_config": {"provider": "custom:myendpoint"}}
|
||||
)
|
||||
assert ov["provider_override"] == "custom:myendpoint"
|
||||
assert ov["model_override"]["provider"] == "custom:myendpoint"
|
||||
|
||||
|
||||
def test_persist_live_session_runtime_preserves_resume_metadata(monkeypatch):
|
||||
updates = {}
|
||||
|
||||
|
|
|
|||
|
|
@ -1477,6 +1477,11 @@ def _resolve_startup_runtime() -> tuple[str, str | None]:
|
|||
return model, None
|
||||
|
||||
|
||||
# Bare billing buckets are not routable provider identities (kept in parity with the
|
||||
# provider gate in agent_init). Restoring one as a session provider override breaks resume.
|
||||
_BARE_BILLING_PROVIDERS = {"auto", "openrouter", "custom"}
|
||||
|
||||
|
||||
def _stored_session_runtime_overrides(row: dict | None) -> dict:
|
||||
"""Return runtime fields persisted with a stored session.
|
||||
|
||||
|
|
@ -1503,12 +1508,18 @@ def _stored_session_runtime_overrides(row: dict | None) -> dict:
|
|||
|
||||
overrides: dict = {}
|
||||
model = str(row.get("model") or model_config.get("model") or "").strip()
|
||||
provider = str(
|
||||
model_config.get("provider")
|
||||
or model_config.get("billing_provider")
|
||||
or row.get("billing_provider")
|
||||
or ""
|
||||
# ``billing_provider`` is only the billing bucket — for a custom endpoint it is the
|
||||
# bare class ``"custom"``, which agent_init treats as non-routable, so restoring it as
|
||||
# the provider override makes ``session.resume`` fail with "No LLM provider configured".
|
||||
# Only restore an explicit provider; otherwise leave it unset so resume falls back to
|
||||
# the configured default, matching the working CLI path.
|
||||
explicit_provider = str(model_config.get("provider") or "").strip()
|
||||
billing_provider = str(
|
||||
model_config.get("billing_provider") or row.get("billing_provider") or ""
|
||||
).strip()
|
||||
provider = explicit_provider
|
||||
if not provider and billing_provider.lower() not in _BARE_BILLING_PROVIDERS:
|
||||
provider = billing_provider
|
||||
base_url = str(model_config.get("base_url") or "").strip()
|
||||
api_mode = str(model_config.get("api_mode") or "").strip()
|
||||
reasoning_config = model_config.get("reasoning_config")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue