From b5030ffb5074219176a62e6edd773af03b09b6a2 Mon Sep 17 00:00:00 2001 From: jan <1760229+slomin@users.noreply.github.com> Date: Wed, 8 Apr 2026 19:47:44 +0100 Subject: [PATCH] fix(runtime): use generic projector repo for non-ByteShape Qwen3.5-9B Routes non-ByteShape Qwen3.5-9B models to the shared `unsloth/Qwen3.5-9B-GGUF` projector repo instead of relying on publisher-specific projector rules. Bumps the pinned `potato-inferno` dependency to the revision that applies the generic 9B mapping and adds API coverage proving `_runtime_env` publishes the expected projector repository for supported 9B models. Closes #263 --- requirements.txt | 2 +- tests/api/test_model_settings.py | 6 ++-- tests/api/test_projector_download.py | 2 +- tests/api/test_runtime_env.py | 44 ++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index 009bdb2..6f0c9fd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,4 @@ uvicorn[standard]>=0.30.0,<1.0.0 httpx>=0.27.0,<1.0.0 psutil>=6.0.0,<7.0.0 PyYAML>=6.0.2,<7.0.0 -potato-inferno @ git+https://github.com/potato-os/inferno.git@5f0b6a0 +potato-inferno @ git+https://github.com/potato-os/inferno.git@2785766 diff --git a/tests/api/test_model_settings.py b/tests/api/test_model_settings.py index b16b3c0..49315d2 100644 --- a/tests/api/test_model_settings.py +++ b/tests/api/test_model_settings.py @@ -20,7 +20,7 @@ def test_update_model_settings_persists_per_model_chat_and_vision(runtime): with TestClient(app) as client: upload = client.post( "/internal/models/upload", - headers={"x-potato-filename": "Qwen3.5-4B-Uncensored-HauhauCS-Aggressive-Q4_K_M.gguf"}, + headers={"x-potato-filename": "Qwen3.5-4B-Q4_K_M.gguf"}, content=b"gguf", ) assert upload.status_code == 200 @@ -74,7 +74,7 @@ def test_settings_document_yaml_round_trip_updates_active_model_and_model_settin with TestClient(app) as client: upload = client.post( "/internal/models/upload", - headers={"x-potato-filename": "Qwen3.5-4B-Uncensored-HauhauCS-Aggressive-Q4_K_M.gguf"}, + headers={"x-potato-filename": "Qwen3.5-4B-Q4_K_M.gguf"}, content=b"gguf", ) assert upload.status_code == 200 @@ -155,7 +155,7 @@ def test_update_model_settings_rejects_invalid_numeric_value(runtime): with TestClient(app) as client: upload = client.post( "/internal/models/upload", - headers={"x-potato-filename": "Qwen3.5-4B-Uncensored-HauhauCS-Aggressive-Q4_K_M.gguf"}, + headers={"x-potato-filename": "Qwen3.5-4B-Q4_K_M.gguf"}, content=b"gguf", ) assert upload.status_code == 200 diff --git a/tests/api/test_projector_download.py b/tests/api/test_projector_download.py index d22fd61..294b619 100644 --- a/tests/api/test_projector_download.py +++ b/tests/api/test_projector_download.py @@ -28,7 +28,7 @@ def _fake_download(*, runtime, model_id: str): with TestClient(app) as client: upload = client.post( "/internal/models/upload", - headers={"x-potato-filename": "Qwen3.5-4B-Uncensored-HauhauCS-Aggressive-Q4_K_M.gguf"}, + headers={"x-potato-filename": "Qwen3.5-4B-Q4_K_M.gguf"}, content=b"gguf", ) assert upload.status_code == 200 diff --git a/tests/api/test_runtime_env.py b/tests/api/test_runtime_env.py index f91bfef..68fad41 100644 --- a/tests/api/test_runtime_env.py +++ b/tests/api/test_runtime_env.py @@ -263,6 +263,50 @@ def test_runtime_env_enables_mmproj_auto_download_when_vision_on_and_no_mmproj(r assert "unsloth" in env["POTATO_HF_MMPROJ_REPO"] or "huggingface" in env["POTATO_HF_MMPROJ_REPO"].lower() +def test_runtime_env_resolves_9b_non_byteshape_to_unsloth_repo(runtime): + """Non-ByteShape Qwen3.5-9B must resolve to unsloth/Qwen3.5-9B-GGUF.""" + model_filename = "Qwen3.5-9B-Q4_K_M.gguf" + model_path = runtime.base_dir / "models" / model_filename + model_path.write_bytes(b"gguf") + runtime.model_path = model_path + runtime.models_state_path.write_text( + json.dumps( + { + "version": 1, + "countdown_enabled": True, + "default_model_downloaded_once": True, + "active_model_id": "default", + "default_model_id": "default", + "current_download_model_id": None, + "models": [ + { + "id": "default", + "filename": model_filename, + "source_url": "https://example.com/qwen35-9b.gguf", + "source_type": "url", + "status": "ready", + "error": None, + "settings": { + "vision": { + "enabled": True, + "projector_mode": "default", + "projector_filename": None, + } + }, + } + ], + } + ), + encoding="utf-8", + ) + + env = _runtime_env(runtime) + + assert env["POTATO_VISION_MODEL_NAME_PATTERN_QWEN35"] == "1" + assert env["POTATO_AUTO_DOWNLOAD_MMPROJ"] == "1" + assert env["POTATO_HF_MMPROJ_REPO"] == "unsloth/Qwen3.5-9B-GGUF" + + def test_projector_status_reports_generic_truthfully_for_offline_compat(runtime): """build_model_projector_status must report mmproj-F16.gguf as present even when model-specific candidates exist — preserves offline upgrades where the