Files
hermes-agent/tests/hermes_cli/test_web_routers_endpoint_probe.py
T
Teknium 734461d213 fix(models): same-URL custom endpoints stop evicting each other's cached catalog; no-probe picker opens revalidate
Two picker-freshness defects in cached_fetch_api_models():

1. The disk cache row was keyed on base_url only, with the credential
   fingerprint stored inside the row. N custom_providers entries sharing
   one proxy URL with different keys (#106184) took turns overwriting the
   single slot; every sibling then failed the fingerprint check, got an
   empty catalog, and disappeared from the Desktop pickers (which hide
   zero-model rows). Key on url#fingerprint so each credential owns a row.

2. cache_only opens (Desktop model.options without refresh) served a
   past-TTL row for up to 7 days without ever revalidating, so a model
   loaded on a non-current local endpoint stayed invisible until the user
   found "Refresh Models". Serve the stale row AND spawn the same
   off-thread SWR refresh the blocking path uses; the caller still never
   waits on the network.

Live repro (two rows, one URL, keys A/B; real loopback /v1/models):
  GUI no-probe open  before {'proxy-a': ['model-A1'], 'proxy-b': ['model-B1']}
                     after  {'proxy-a': ['model-A1','model-A2'], 'proxy-b': ['model-B1']}
2026-09-09 03:33:06 -07:00

67 lines
2.3 KiB
Python

"""Endpoint-probe contract for the Desktop local/custom endpoint validators (#63472).
httpx honours ``HTTP(S)_PROXY`` (and the Windows system proxy) but never the proxy bypass list,
so a system proxy answered ``127.0.0.1`` probes with its own error page. The GUI then reported
"advertised no models" for a llama.cpp server the CLI (urllib, honours the bypass) saw fine.
"""
from __future__ import annotations
import asyncio
import pytest
@pytest.mark.parametrize(
"url, trusts_env",
[
("http://127.0.0.1:8080/v1/models", False),
("http://localhost:11434/v1/models", False),
("http://192.168.1.20:8000/v1/models", False),
("https://api.example.com/v1/models", True),
],
)
def test_local_endpoint_probes_bypass_env_proxy(url, trusts_env, monkeypatch):
from hermes_cli.web_routers.config_env import _endpoint_probe_client
monkeypatch.setenv("HTTPS_PROXY", "http://127.0.0.1:1")
monkeypatch.setenv("HTTP_PROXY", "http://127.0.0.1:1")
client = _endpoint_probe_client(url, 1.0)
assert client.trust_env is trusts_env
def test_openai_base_url_probe_names_the_http_status_instead_of_no_models(monkeypatch):
"""A reachable endpoint answering non-2xx with no model list is a failure the user can act on,
not an empty catalog the GUI turns into 'start a model on that endpoint'."""
import hermes_cli.web_routers.config_env as mod
from hermes_cli.web_models import EnvVarUpdate
class _Resp:
status_code = 502
is_success = False
def json(self):
return {"error": "proxy upstream unavailable"}
class _Client:
def __init__(self, *a, **k):
pass
async def __aenter__(self):
return self
async def __aexit__(self, *a):
return False
async def get(self, *a, **k):
return _Resp()
monkeypatch.setattr(mod, "_endpoint_probe_client", lambda url, timeout: _Client())
monkeypatch.setattr(mod, "_require_token", lambda request: None)
body = EnvVarUpdate(key="OPENAI_BASE_URL", value="http://127.0.0.1:8080/v1", api_key="")
out = asyncio.run(mod.validate_provider_credential(body, request=None)) # type: ignore[arg-type]
assert out["ok"] is False and out["reachable"] is True
assert "HTTP 502" in out["message"]