Merge PR #1415 from Thanatos-Z: fix named custom provider routing in model picker

This commit is contained in:
nesquena-hermes
2026-05-01 18:20:07 +00:00
4 changed files with 94 additions and 1 deletions
+4 -1
View File
@@ -1966,8 +1966,11 @@ def get_available_models() -> dict:
if _slug not in _named_custom_groups:
_named_custom_groups[_slug] = (_cp_name, [])
detected_providers.add(_slug)
_cp_option_id = _cp_model
if active_provider != _slug and not _cp_option_id.startswith("@"):
_cp_option_id = f"@{_slug}:{_cp_option_id}"
_named_custom_groups[_slug][1].append(
{"id": _cp_model, "label": _cp_label}
{"id": _cp_option_id, "label": _cp_label}
)
else:
auto_detected_models.append({"id": _cp_model, "label": _cp_label})
@@ -196,3 +196,26 @@ class TestCustomProvidersModelsDict:
# No cross-contamination
assert "model-b1" not in ids_a
assert "model-a1" not in ids_b
def test_named_custom_models_are_prefixed_when_not_active_provider(self):
"""Named custom provider models must carry a routing prefix when DeepSeek is active."""
result = _models_with_cfg(
model_cfg={"provider": "deepseek", "default": "deepseek-v4-pro"},
custom_providers=[
{
"name": "sub2api",
"base_url": "http://127.0.0.1:8080/v1",
"model": "gpt-5.4-mini",
"models": {
"gpt-5.4-mini": {},
"gpt-5.4": {},
},
}
],
)
group = _group_for(result, "sub2api")
assert group is not None, "sub2api group missing"
assert group["provider_id"] == "custom:sub2api"
ids = [m["id"] for m in group["models"]]
assert "@custom:sub2api:gpt-5.4-mini" in ids
assert "@custom:sub2api:gpt-5.4" in ids
+43
View File
@@ -751,6 +751,49 @@ def test_issue1253_duplicate_model_id_active_provider_hint_preserved(monkeypatch
)
def test_named_custom_provider_hint_with_colon_is_preserved(monkeypatch):
"""@custom:name:model must survive chat/start normalization for WebUI routing."""
import api.routes as routes
monkeypatch.setattr(
routes,
"get_available_models",
lambda: {
"active_provider": "deepseek",
"default_model": "deepseek-v4-pro",
"groups": [
{
"provider": "sub2api",
"provider_id": "custom:sub2api",
"models": [
{
"id": "@custom:sub2api:gpt-5.4-mini",
"label": "GPT 5.4 Mini",
}
],
},
{
"provider": "DeepSeek",
"provider_id": "deepseek",
"models": [
{
"id": "deepseek-v4-pro",
"label": "DeepSeek V4 Pro",
}
],
},
],
},
)
effective, changed = routes._resolve_compatible_session_model(
"@custom:sub2api:gpt-5.4-mini"
)
assert changed is False
assert effective == "@custom:sub2api:gpt-5.4-mini"
def test_stale_at_provider_model_falls_back_when_family_mismatches(monkeypatch):
"""Unroutable @provider:model should not invent a bare model for another family."""
import api.routes as routes
+24
View File
@@ -11,8 +11,10 @@ Tests run against the isolated test test_server on port 8788.
"""
import json
import importlib
import pathlib
import sys
import types
import urllib.request
import urllib.error
import pytest
@@ -105,6 +107,28 @@ def test_redact_value_list():
assert result[1]["content"] == "safe text"
def test_redact_value_works_with_legacy_agent_redact_signature(monkeypatch):
"""_redact_text must tolerate older redact_sensitive_text(text) signatures."""
fake_agent = types.ModuleType("agent")
fake_redact = types.ModuleType("agent.redact")
def _legacy_redact_sensitive_text(text):
return text
fake_redact.redact_sensitive_text = _legacy_redact_sensitive_text
monkeypatch.setitem(sys.modules, "agent", fake_agent)
monkeypatch.setitem(sys.modules, "agent.redact", fake_redact)
import api.helpers as helpers
helpers = importlib.reload(helpers)
try:
result = helpers._redact_value(f"token={_FAKE_GITHUB_PAT}")
assert _FAKE_GITHUB_PAT not in result
assert "ghp_Te" in result
finally:
importlib.reload(helpers)
def test_redact_session_data_messages():
"""redact_session_data masks credentials in messages[]."""
from api.helpers import redact_session_data