agharsallah commited on
Commit ·
66f0e23
1
Parent(s): eed2172
feat: update HF model catalogue to prioritize chat-capable model and adjust tests for new routing logic
Browse files- src/models/hf_catalogue.py +13 -15
- tests/test_hf_catalogue.py +8 -5
- tests/test_inference_backends.py +3 -1
- tests/test_router.py +6 -5
src/models/hf_catalogue.py
CHANGED
|
@@ -69,21 +69,19 @@ class HFModel:
|
|
| 69 |
# router shifts over time; because this is plain data, retuning is a one-line edit.
|
| 70 |
|
| 71 |
HF_MODELS: tuple[HFModel, ...] = (
|
| 72 |
-
#
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
#
|
| 78 |
-
HFModel("
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
#
|
| 82 |
-
|
| 83 |
-
#
|
| 84 |
-
|
| 85 |
-
HFModel("mistralai/Mistral-Small-24B-Instruct-2501", params_b=24, source="Mistral"),
|
| 86 |
-
HFModel("Qwen/Qwen2.5-14B-Instruct", params_b=14, source="Qwen"),
|
| 87 |
)
|
| 88 |
|
| 89 |
|
|
|
|
| 69 |
# router shifts over time; because this is plain data, retuning is a one-line edit.
|
| 70 |
|
| 71 |
HF_MODELS: tuple[HFModel, ...] = (
|
| 72 |
+
# Only chat-capable model currently live on the enabled HF providers (free
|
| 73 |
+
# `hf-inference`), verified by a real /v1/chat/completions call. Pinned to its
|
| 74 |
+
# provider so the router does not depend on paid-provider auto-routing. It is
|
| 75 |
+
# tagged `tiny` (1.5B, ≤4B band) but serves every tier: a tier with no dedicated
|
| 76 |
+
# HF model falls back to the first catalogue entry (see lab._default_model_key),
|
| 77 |
+
# so the whole cast routes here while only `hf-inference` is enabled.
|
| 78 |
+
HFModel("katanemo/Arch-Router-1.5B", profile="tiny", params_b=1.5, source="Katanemo", hf_provider="hf-inference"),
|
| 79 |
+
# NOTE: to use larger small models (e.g. openai/gpt-oss-20b — 20B, ≤32B, OpenAI
|
| 80 |
+
# track) enable a provider that serves them (together / nscale / fireworks /
|
| 81 |
+
# novita / groq) at https://huggingface.co/settings/inference-providers, then add
|
| 82 |
+
# the model here. `HuggingFaceBio/Carbon-3B` is intentionally NOT listed: the HF
|
| 83 |
+
# router rejects it as "not a chat model" (it is text-generation only), so it
|
| 84 |
+
# cannot drive the chat-completions path the engine uses.
|
|
|
|
|
|
|
| 85 |
)
|
| 86 |
|
| 87 |
|
tests/test_hf_catalogue.py
CHANGED
|
@@ -31,15 +31,18 @@ def test_every_model_is_within_its_tier_param_cap():
|
|
| 31 |
assert params <= _TIER_CAP[tier], f"{e['key']} ({params}B) exceeds {tier} cap"
|
| 32 |
|
| 33 |
|
| 34 |
-
def
|
| 35 |
-
|
| 36 |
-
|
|
|
|
|
|
|
| 37 |
|
| 38 |
|
| 39 |
def test_binding_uses_router_url_and_token():
|
| 40 |
-
key = hf_catalogue.default_key_for_profile("
|
| 41 |
binding = hf_catalogue.binding_for(key, env={"HF_TOKEN": "hf_xyz"})
|
| 42 |
-
|
|
|
|
| 43 |
assert binding["base_url"] == hf_catalogue.DEFAULT_BASE_URL
|
| 44 |
assert binding["api_key"] == "hf_xyz"
|
| 45 |
|
|
|
|
| 31 |
assert params <= _TIER_CAP[tier], f"{e['key']} ({params}B) exceeds {tier} cap"
|
| 32 |
|
| 33 |
|
| 34 |
+
def test_catalogue_has_a_tiny_default():
|
| 35 |
+
# The catalogue is currently scoped to the one chat-capable model live on the
|
| 36 |
+
# enabled providers (tagged tiny). Tiers without a dedicated model fall back to
|
| 37 |
+
# it at the UI layer (see lab._default_model_key), so they may return None here.
|
| 38 |
+
assert hf_catalogue.default_key_for_profile("tiny") == "katanemo/Arch-Router-1.5B"
|
| 39 |
|
| 40 |
|
| 41 |
def test_binding_uses_router_url_and_token():
|
| 42 |
+
key = hf_catalogue.default_key_for_profile("tiny")
|
| 43 |
binding = hf_catalogue.binding_for(key, env={"HF_TOKEN": "hf_xyz"})
|
| 44 |
+
# The model pins its provider (hf-inference) so routing needs no paid auto-select.
|
| 45 |
+
assert binding["model"] == f"openai/{key}:hf-inference"
|
| 46 |
assert binding["base_url"] == hf_catalogue.DEFAULT_BASE_URL
|
| 47 |
assert binding["api_key"] == "hf_xyz"
|
| 48 |
|
tests/test_inference_backends.py
CHANGED
|
@@ -64,7 +64,9 @@ def test_binding_dispatches_to_the_right_backend():
|
|
| 64 |
|
| 65 |
|
| 66 |
def test_default_key_for_profile_is_backend_scoped():
|
| 67 |
-
|
|
|
|
|
|
|
| 68 |
assert hf_default is not None and hf_default.startswith("hf:")
|
| 69 |
modal_default = inference.default_key_for_profile("strong", "modal")
|
| 70 |
assert modal_default is not None and not modal_default.startswith("hf:")
|
|
|
|
| 64 |
|
| 65 |
|
| 66 |
def test_default_key_for_profile_is_backend_scoped():
|
| 67 |
+
# HF currently tags only the tiny tier (its single live chat model); Modal tags
|
| 68 |
+
# every tier. The point here is that keys are namespaced per backend.
|
| 69 |
+
hf_default = inference.default_key_for_profile("tiny", "hf")
|
| 70 |
assert hf_default is not None and hf_default.startswith("hf:")
|
| 71 |
modal_default = inference.default_key_for_profile("strong", "modal")
|
| 72 |
assert modal_default is not None and not modal_default.startswith("hf:")
|
tests/test_router.py
CHANGED
|
@@ -111,17 +111,18 @@ class TestModelRouterCatalogueEndpoint:
|
|
| 111 |
|
| 112 |
def test_online_hf_endpoint_key_resolves_to_hf_router(self, monkeypatch):
|
| 113 |
# A backend-qualified HF key resolves to the HF Inference router binding —
|
| 114 |
-
# the OpenAI-compatible model string + HF token, no Modal env needed.
|
|
|
|
| 115 |
monkeypatch.setenv("HF_TOKEN", "hf_secret")
|
| 116 |
monkeypatch.delenv("HF_INFERENCE_BASE_URL", raising=False)
|
| 117 |
-
monkeypatch.delenv("
|
| 118 |
router = ModelRouter(offline=False)
|
| 119 |
-
provider = router.for_profile("hf:
|
| 120 |
assert isinstance(provider, LiteLLMProvider)
|
| 121 |
-
assert provider.model == "openai/
|
| 122 |
assert provider.api_base == "https://router.huggingface.co/v1"
|
| 123 |
assert provider.api_key == "hf_secret"
|
| 124 |
-
assert provider.max_tokens ==
|
| 125 |
|
| 126 |
def test_offline_hf_endpoint_key_serves_distinct_stub(self):
|
| 127 |
# Offline, an HF key routes like any profile: the deterministic stub with the
|
|
|
|
| 111 |
|
| 112 |
def test_online_hf_endpoint_key_resolves_to_hf_router(self, monkeypatch):
|
| 113 |
# A backend-qualified HF key resolves to the HF Inference router binding —
|
| 114 |
+
# the OpenAI-compatible model string + HF token, no Modal env needed. The
|
| 115 |
+
# model pins its provider (hf-inference) so routing needs no paid auto-select.
|
| 116 |
monkeypatch.setenv("HF_TOKEN", "hf_secret")
|
| 117 |
monkeypatch.delenv("HF_INFERENCE_BASE_URL", raising=False)
|
| 118 |
+
monkeypatch.delenv("MODEL_TINY", raising=False)
|
| 119 |
router = ModelRouter(offline=False)
|
| 120 |
+
provider = router.for_profile("hf:katanemo/Arch-Router-1.5B")
|
| 121 |
assert isinstance(provider, LiteLLMProvider)
|
| 122 |
+
assert provider.model == "openai/katanemo/Arch-Router-1.5B:hf-inference"
|
| 123 |
assert provider.api_base == "https://router.huggingface.co/v1"
|
| 124 |
assert provider.api_key == "hf_secret"
|
| 125 |
+
assert provider.max_tokens == 192 # tiny tier decoding (the model's tier)
|
| 126 |
|
| 127 |
def test_offline_hf_endpoint_key_serves_distinct_stub(self):
|
| 128 |
# Offline, an HF key routes like any profile: the deterministic stub with the
|