B7: Apple Silicon worker support (v0.19.0)

gpu.py: darwin branch via system_profiler SPDisplaysDataType for GPU
model/VRAM on macOS, falls back to rocm-smi on Linux.
hardware.py: _get_vram_darwin() parses system_profiler output.
node_agent/agent.py: get_load() reports VRAM on darwin via
system_profiler.
tests: 5 new gpu tests (linux/darwin/absent), 3 new hardware tests
(darwin assessment + VRAM parsing).
This commit is contained in:
gramps
2026-07-14 08:09:41 -07:00
parent feaa2830da
commit 790c81457a
7 changed files with 273 additions and 13 deletions
+60
View File
@@ -2,6 +2,7 @@ import asyncio
import json
import os
import subprocess
import sys
from pathlib import Path
import httpx
@@ -174,3 +175,62 @@ def test_get_hardware_endpoint(tmp_path: Path, monkeypatch):
assert data["searxng_reachable"] is True
assert "llama_models" in data
assert "qdrant_collections" in data
def test_assess_hardware_darwin(tmp_path: Path, monkeypatch):
hardware.HARDWARE_STATE_PATH = tmp_path / "hardware_state.json"
monkeypatch.setattr(psutil, "virtual_memory", lambda: type("M", (), {"total": 16 * 1024 ** 3, "available": 8 * 1024 ** 3})())
monkeypatch.setattr(psutil, "cpu_count", lambda: 8)
monkeypatch.setattr(sys, "platform", "darwin")
monkeypatch.setattr(hardware, "_get_vram_darwin", lambda: (16384, 16384))
async def mock_get(self, url, *args, **kwargs):
if "v1/models" in url:
return _MockGet(200, {"data": [{"id": "qwen2.5:latest"}]})
if "6333" in url:
return _MockGet(200, {"result": {"collections": [{"name": "caic"}]}})
if "8888" in url:
return _MockGet(200, {})
return _MockGet(200, {})
monkeypatch.setattr(httpx.AsyncClient, "get", mock_get)
state = asyncio.run(hardware.assess_hardware())
assert state["vram_total_mb"] == 16384
assert state["vram_free_mb"] == 16384
assert state["ram_total_gb"] == 16.0
assert state["llama_reachable"] is True
def test_get_vram_darwin_parse(monkeypatch):
sp_output = """Graphics/Displays:
Apple M2 Pro:
Chipset Model: Apple M2 Pro
VRAM (Dynamic, Max): 16 GB
"""
class MockProc:
returncode = 0
stdout = sp_output
class MockSP:
TimeoutExpired = subprocess.TimeoutExpired
run = staticmethod(lambda cmd, **kw: MockProc())
monkeypatch.setattr(hardware, "subprocess", MockSP())
total, free = hardware._get_vram_darwin()
assert total == 16384
assert free == 16384
def test_get_vram_darwin_system_profiler_absent(monkeypatch):
class MockSP:
TimeoutExpired = subprocess.TimeoutExpired
run = staticmethod(lambda cmd, **kw: (_ for _ in ()).throw(FileNotFoundError("no system_profiler")))
monkeypatch.setattr(hardware, "subprocess", MockSP())
total, free = hardware._get_vram_darwin()
assert total == 0
assert free == 0