Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ods/extensions/services/dashboard-api/routers/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ def _configured_model_identity_matches(model: dict) -> bool:
)
if not (_model_name_tokens(configured_llm) & _catalog_model_tokens(model)):
return False
if not (Path(DATA_DIR) / "models" / gguf_file).exists():
if _installed_model_path(gguf_file) is None:
return False
return True

Expand Down
65 changes: 65 additions & 0 deletions ods/extensions/services/dashboard-api/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import time
import types
import httpx
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
from unittest.mock import AsyncMock

Expand Down Expand Up @@ -1564,6 +1565,70 @@ def fail_agent_call(*_args, **_kwargs):
}


@pytest.mark.parametrize("files", ["registered", "missing", "ambiguous"])
@pytest.mark.parametrize("portal_active", [False, True])
def test_load_registered_active_model_requires_unique_installed_artifact(
test_client, monkeypatch, tmp_path, files, portal_active,
):
router, install_dir, data_dir = _patch_model_router_paths(monkeypatch, tmp_path)
path_exists = Path.exists
monkeypatch.setattr(Path, "exists", lambda path:
False if path == Path("/.dockerenv") else path_exists(path))
model = {
"id": "ssd-model", "name": "SSD model", "gguf_file": "ssd-model.gguf",
"llm_model_name": "ssd-model", "context_length": 32768,
}
_write_model_library(install_dir, [model])
store = tmp_path / "ssd-models"
store.mkdir()
(data_dir / "model-stores.json").write_text(json.dumps({
"schemaVersion": 1, "stores": [{
"id": "ssd", "hostPath": str(store), "containerPath": "/model-stores/ssd",
}],
}), encoding="utf-8")
if files != "missing":
(store / model["gguf_file"]).write_bytes(b"installed-model")
if files == "ambiguous":
(data_dir / "models" / model["gguf_file"]).write_bytes(b"different-model")
(install_dir / ".env").write_text(
"ODS_MODE=local\nLLM_BACKEND=llama-server\nODS_ACTIVE_MODEL_STORE=ssd\n"
"GGUF_FILE=ssd-model.gguf\nLLM_MODEL=ssd-model\nCTX_SIZE=32768\n",
encoding="utf-8",
)
_write_activation_receipt(data_dir, model["id"], model["gguf_file"])
receipt_path = data_dir / "model-activation-receipt.json"
receipt = json.loads(receipt_path.read_text(encoding="utf-8"))
receipt.update(contextVerified=True, contextLength=32768)
receipt_path.write_text(json.dumps(receipt), encoding="utf-8")
monkeypatch.setattr(router, "LLM_BACKEND", "llama-server")
monkeypatch.setattr(router, "_fetch_loaded_model_sync", lambda: model["gguf_file"])
monkeypatch.setattr(router, "pixel_stream_active", lambda: portal_active)
monkeypatch.setattr(router, "_bootstrap_upgrade_download_conflict", lambda: None)
activations = []
def activate(*args, **kwargs):
activations.append(args)
return {"status": "activated"}
monkeypatch.setattr(router, "_call_agent_model", activate)

response = test_client.post(
"/api/models/ssd-model/load", json={"context_length": 32768},
headers=test_client.auth_headers,
)

if files == "registered":
assert response.status_code == 200
assert response.json()["status"] == "already_active"
assert activations == []
elif portal_active:
assert response.status_code == 409
assert response.json()["detail"]["code"] == "pixel_chat_active"
assert activations == []
else:
assert response.status_code == 200
assert response.json()["status"] == "activated"
assert len(activations) == 1


def test_get_gpu_vram_returns_none_on_nvml_error(monkeypatch):
"""Operational NVML failures should degrade to unknown GPU rather than 500."""

Expand Down
Loading