Files
hermes-webui/tests/test_issue3717_context_length_provider_overrides.py
T
nesquena-hermesandnesquena-hermes 1cb9d3b550 fix(#3717): context-length indicator honors provider per-model overrides (#3726) (#3752)
@rodboev. providers.<name>.models.<model>.context_length overrides (standard provider,
no base_url) were invisible to the session context resolver → wrong window shown/persisted,
could trip auto-compression at the wrong threshold. New _context_length_lookup_inputs_for_model
helper resolves provider config / base_url / custom_providers across route-load, session-save,
and SSE-usage paths; provider-scoped overrides match by provider name and forward as
config_context_length (returned before any base-url-gated probe).

Maintainer pre-merge items both already satisfied in PR head: no-base_url regression test
(test_route_resolver_uses_provider_model_context_length_without_base_url) present; session-save
_cfg_base_url assigned before the helper call (safe-bound, no NameError on TypeError fallback).
Verified api code byte-identical to PR head; 14 context-length tests pass. + CHANGELOG v0.51.300.

Co-authored-by: nesquena-hermes <[email protected]>
2026-06-06 15:57:09 -07:00

199 lines
5.9 KiB
Python

"""Regression coverage for #3717 provider-scoped context-length overrides."""
import sys
import types
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
STREAMING_PY = (REPO / "api" / "streaming.py").read_text(encoding="utf-8")
ROUTES_PY = (REPO / "api" / "routes.py").read_text(encoding="utf-8")
def _install_fake_context_resolver(monkeypatch):
calls = []
mod = types.ModuleType("agent.model_metadata")
def _fake(
model,
base_url="",
*args,
config_context_length=None,
provider="",
custom_providers=None,
**kwargs,
):
calls.append(
{
"model": model,
"base_url": base_url,
"config_context_length": config_context_length,
"provider": provider,
"custom_providers": custom_providers,
}
)
return config_context_length or 256000
mod.get_model_context_length = _fake
if "agent" not in sys.modules:
agent_pkg = types.ModuleType("agent")
agent_pkg.__path__ = []
monkeypatch.setitem(sys.modules, "agent", agent_pkg)
monkeypatch.setitem(sys.modules, "agent.model_metadata", mod)
return calls
def test_route_resolver_uses_provider_model_context_length(monkeypatch):
import api.config as config
import api.routes as routes
calls = _install_fake_context_resolver(monkeypatch)
monkeypatch.setattr(
config,
"get_config",
lambda *a, **k: {
"model": {
"default": "default-model",
"context_length": 123456,
},
"providers": {
"openrouter": {
"base_url": "https://openrouter.example/v1",
"models": {
"provider-model": {"context_length": 777000},
},
},
},
"custom_providers": [],
},
)
result = routes._resolve_context_length_for_session_model(
"provider-model",
"openrouter",
)
assert result == 777000
assert calls[-1]["config_context_length"] == 777000
assert calls[-1]["base_url"] == "https://openrouter.example/v1"
assert calls[-1]["provider"] == "openrouter"
def test_route_resolver_uses_provider_model_context_length_without_base_url(monkeypatch):
import api.config as config
import api.routes as routes
calls = _install_fake_context_resolver(monkeypatch)
monkeypatch.setattr(
config,
"get_config",
lambda *a, **k: {
"model": {
"default": "default-model",
"context_length": 123456,
},
"providers": {
"anthropic": {
"models": {
"provider-model": {"context_length": 777000},
},
},
},
"custom_providers": [],
},
)
result = routes._resolve_context_length_for_session_model(
"provider-model",
"anthropic",
)
assert result == 777000
assert calls[-1]["config_context_length"] == 777000
assert calls[-1]["base_url"] == ""
assert calls[-1]["provider"] == "anthropic"
def test_route_resolver_uses_named_custom_provider_base_url(monkeypatch):
import api.config as config
import api.routes as routes
custom_providers = [
{
"name": "ZenMux",
"base_url": "https://zenmux.example/v1",
"models": {
"custom-model": {"context_length": "888000"},
},
}
]
calls = _install_fake_context_resolver(monkeypatch)
monkeypatch.setattr(
config,
"get_config",
lambda *a, **k: {
"model": {
"default": "default-model",
"context_length": 123456,
},
"custom_providers": custom_providers,
},
)
result = routes._resolve_context_length_for_session_model(
"custom-model",
"custom:zenmux",
)
assert result == 888000
assert calls[-1]["config_context_length"] == 888000
assert calls[-1]["base_url"] == "https://zenmux.example/v1"
assert calls[-1]["provider"] == "custom:zenmux"
assert calls[-1]["custom_providers"] is custom_providers
def test_global_context_length_remains_default_model_only(monkeypatch):
import api.config as config
import api.routes as routes
calls = _install_fake_context_resolver(monkeypatch)
monkeypatch.setattr(
config,
"get_config",
lambda *a, **k: {
"model": {
"default": "default-model",
"context_length": 123456,
},
"providers": {
"openai": {
"base_url": "https://openai.example/v1",
"models": {},
},
},
},
)
result = routes._resolve_context_length_for_session_model("other-model", "openai")
assert result == 256000
assert calls[-1]["config_context_length"] is None
assert calls[-1]["base_url"] == "https://openai.example/v1"
def test_streaming_fallbacks_use_shared_provider_context_helper():
assert STREAMING_PY.count("_context_length_lookup_inputs_for_model(") >= 2
assert "_cfg_base_url = getattr(agent, 'base_url', '') or resolved_base_url or ''" in STREAMING_PY
assert "base_url=_cfg_base_url" in STREAMING_PY
assert "config_context_length=_cfg_ctx_len" in STREAMING_PY
assert "provider=_cfg_provider" in STREAMING_PY
assert "custom_providers=_cfg_custom_providers" in STREAMING_PY
assert "_cfg_base_url" in STREAMING_PY
def test_route_helper_keeps_all_context_length_sources_aligned():
assert "def _context_length_lookup_inputs_for_model" in ROUTES_PY
assert 'cfg.get("providers", {})' in ROUTES_PY
assert 'cfg.get("custom_providers")' in ROUTES_PY
assert "_model_matches_configured_default" in ROUTES_PY