commit
43cdd7cc37
3 changed files with 27 additions and 1 deletions
|
|
@ -6,6 +6,7 @@
|
|||
### Fixed
|
||||
|
||||
- Dark-mode panel header save buttons now use a theme-aware foreground token, keeping workspace and other detail-pane check icons visible on the default gold accent. (#2998)
|
||||
- Custom provider `/v1/models` discovery now uses a short per-endpoint timeout and gracefully skips slow or unreachable providers, reducing cold `/api/models` cache rebuild latency. (#3024)
|
||||
|
||||
## [v0.51.145] — 2026-05-26 — Release DQ (stage-batch27 — sidebar running-state preservation)
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,12 @@ PROJECTS_FILE = STATE_DIR / "projects.json"
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Keep custom provider /v1/models probes below the frontend's generic request
|
||||
# timeout even when one upstream is slow or unreachable. The models cache rebuild
|
||||
# path probes configured custom endpoints serially, so each provider needs a
|
||||
# short hard cap and graceful degradation.
|
||||
CUSTOM_MODELS_ENDPOINT_TIMEOUT_SECONDS = 5.0
|
||||
|
||||
|
||||
def _env_mb_bytes(name: str, default_mb: int) -> int:
|
||||
"""Parse an optional megabyte environment variable into bytes.
|
||||
|
|
@ -3653,7 +3659,7 @@ def get_available_models() -> dict:
|
|||
req.add_header("User-Agent", "OpenAI/Python 1.0")
|
||||
for k, v in headers.items():
|
||||
req.add_header(k, v)
|
||||
with urllib.request.urlopen(req, timeout=10) as response: # nosec B310
|
||||
with urllib.request.urlopen(req, timeout=CUSTOM_MODELS_ENDPOINT_TIMEOUT_SECONDS) as response: # nosec B310
|
||||
data = json.loads(response.read().decode("utf-8"))
|
||||
return _extract_model_entries_from_payload(data, provider), None
|
||||
except urllib.error.HTTPError as exc:
|
||||
|
|
|
|||
|
|
@ -112,6 +112,25 @@ def test_named_custom_provider_models_endpoint_5xx_preserves_status(monkeypatch,
|
|||
assert error["code"] == 502
|
||||
assert "returned 502" in error["message"]
|
||||
|
||||
def test_named_custom_provider_models_endpoint_network_error_uses_short_timeout(monkeypatch, tmp_path):
|
||||
observed_timeouts = []
|
||||
|
||||
def fake_urlopen(req, timeout=10):
|
||||
observed_timeouts.append(timeout)
|
||||
raise urllib.error.URLError("timed out")
|
||||
|
||||
monkeypatch.setattr(urllib.request, "urlopen", fake_urlopen)
|
||||
|
||||
with _ConfigState():
|
||||
_configure_named_custom_provider(tmp_path, monkeypatch)
|
||||
data = config.get_available_models()
|
||||
|
||||
group = _groups_by_provider(data)["custom:broken-proxy"]
|
||||
assert group["models"] == []
|
||||
assert group["models_endpoint_error"]["kind"] == "network"
|
||||
assert observed_timeouts == [config.CUSTOM_MODELS_ENDPOINT_TIMEOUT_SECONDS]
|
||||
assert max(observed_timeouts) <= 5.0
|
||||
|
||||
|
||||
def test_frontend_model_picker_renders_provider_endpoint_hint():
|
||||
ui = open("static/ui.js", encoding="utf-8").read()
|
||||
|
|
|
|||
Loading…
Reference in a new issue