From 8ce96df66f7eb98101f5f77909b6fcd383d9ed4a Mon Sep 17 00:00:00 2001 From: Roland Tannous Date: Fri, 13 Feb 2026 20:54:40 +0000 Subject: [PATCH] fix: auto-detect LoRA adapters for both local and remote HF models in ModelConfig --- studio/backend/utils/models/model_config.py | 36 ++++++++++++++++++- studio/tests/test_remote_lora_detection.py | 40 +++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 studio/tests/test_remote_lora_detection.py diff --git a/studio/backend/utils/models/model_config.py b/studio/backend/utils/models/model_config.py index ef8ebf5d4e..5882f41e2a 100644 --- a/studio/backend/utils/models/model_config.py +++ b/studio/backend/utils/models/model_config.py @@ -661,10 +661,44 @@ class ModelConfig: identifier = f"unsloth/{identifier}" path = identifier + # Auto-detect LoRA for local paths (check adapter_config.json on disk) + if not is_lora and is_local: + detected_base = get_base_model_from_lora(path) + if detected_base: + is_lora = True + logger.info(f"Auto-detected local LoRA adapter at '{path}' (base: {detected_base})") + + # Auto-detect LoRA for remote HF models (check repo file listing) + if not is_lora and not is_local: + try: + from huggingface_hub import model_info as hf_model_info + info = hf_model_info(identifier, token=hf_token) + repo_files = [s.rfilename for s in info.siblings] + if "adapter_config.json" in repo_files: + is_lora = True + logger.info(f"Auto-detected remote LoRA adapter: '{identifier}'") + except Exception as e: + logger.debug(f"Could not check remote LoRA status for '{identifier}': {e}") + # Handle LoRA adapters base_model = None if is_lora: - base_model = get_base_model_from_lora(path) + if is_local: + # Local LoRA: read adapter_config.json from disk + base_model = get_base_model_from_lora(path) + else: + # Remote LoRA: download adapter_config.json from HF + try: + from huggingface_hub import hf_hub_download + config_path = hf_hub_download(identifier, "adapter_config.json", token=hf_token) + with open(config_path, 'r') as f: + adapter_config = json.load(f) + base_model = adapter_config.get("base_model_name_or_path") + if base_model: + logger.info(f"Resolved remote LoRA base model: '{base_model}'") + except Exception as e: + logger.warning(f"Could not download adapter_config.json for '{identifier}': {e}") + if not base_model: logger.warning(f"Could not determine base model for LoRA '{path}'") return None diff --git a/studio/tests/test_remote_lora_detection.py b/studio/tests/test_remote_lora_detection.py new file mode 100644 index 0000000000..870758e76e --- /dev/null +++ b/studio/tests/test_remote_lora_detection.py @@ -0,0 +1,40 @@ +""" +Test remote LoRA adapter detection via HuggingFace Hub API. + +Verifies that we can detect whether a remote HF model is a LoRA adapter +by checking for adapter_config.json in the repo file listing. +""" +import pytest +from huggingface_hub import model_info + + +def is_remote_lora_adapter(model_id: str, hf_token: str = None) -> bool: + """ + Check if a remote HuggingFace model is a LoRA adapter + by looking for adapter_config.json in its repo files. + """ + try: + info = model_info(model_id, token=hf_token) + filenames = [s.rfilename for s in info.siblings] + return "adapter_config.json" in filenames + except Exception: + return False + + +class TestRemoteLoRADetection: + """Test remote LoRA adapter detection via HF Hub API.""" + + def test_lora_adapter_detected(self): + """edbeeching/llama-se-rl-adapter is a known LoRA adapter on HF.""" + result = is_remote_lora_adapter("edbeeching/llama-se-rl-adapter") + assert result is True, "Expected edbeeching/llama-se-rl-adapter to be detected as a LoRA adapter" + + def test_base_model_not_detected_as_lora(self): + """google/gemma-3-4b-it is a full base model, not a LoRA adapter.""" + result = is_remote_lora_adapter("google/gemma-3-4b-it") + assert result is False, "Expected google/gemma-3-4b-it to NOT be detected as a LoRA adapter" + + def test_nonexistent_model_returns_false(self): + """A nonexistent model should return False, not raise.""" + result = is_remote_lora_adapter("this-org-does-not-exist/fake-model-12345") + assert result is False, "Expected nonexistent model to return False"