feat: add cross-platform hardware block to comfy env --json (BE-3399)#562
feat: add cross-platform hardware block to comfy env --json (BE-3399)#562mattmillerai wants to merge 5 commits into
Conversation
Add comfy_cli/hardware.py with a single detect_hardware() entry point that reports OS, CPU, RAM, and a GPU sub-block (vendor/model/VRAM/unified-memory) so agent surfaces can route weak machines away from local diffusion. - macOS: cpu via sysctl machdep.cpu.brand_string; Apple Silicon -> apple unified-memory GPU; Intel Mac -> unknown non-unified GPU (no system_profiler). - NVIDIA (any OS): nvidia-smi CSV, then ctypes libcuda fallback (reuses cuda_detect._load_libcuda). - AMD (Linux): best-effort rocm-smi --json. - Never raises, never blocks long: every probe wrapped, subprocesses timeout=5. Wire hardware into EnvChecker.fill_data() (JSON) and a Hardware row in fill_print_table() (pretty). Extend schemas/env.json with an OPTIONAL, fully nullable hardware property (not in required) so older/failed-probe payloads stay valid. Envelope schema unchanged (envelope/1).
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 33 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughChangesHardware probing is added for operating system, CPU, RAM, NVIDIA, AMD, and Apple Silicon GPU details. Hardware Environment Reporting
Sequence Diagram(s)sequenceDiagram
participant CLI
participant EnvChecker
participant detect_hardware
participant SystemProbes
participant GPUProbes
CLI->>EnvChecker: run environment check
EnvChecker->>detect_hardware: collect hardware
detect_hardware->>SystemProbes: read platform, CPU, and RAM
detect_hardware->>GPUProbes: probe NVIDIA, AMD, or Apple GPU
detect_hardware-->>EnvChecker: return hardware dict
EnvChecker-->>CLI: render table or JSON output
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Comment |
There was a problem hiding this comment.
🔍 Cursor Review — Consolidated panel
Triggered by @mattmillerai.
Found 9 finding(s).
| Severity | Count |
|---|---|
| 🟡 Medium | 4 |
| 🟢 Low | 4 |
| ⚪ Nit | 1 |
Panel: 6/8 reviewers contributed findings.
Reviewers that did not contribute: kimi-k2.5:adversarial (empty), kimi-k2.5:edge-case (empty)
…(BE-3399) - env_checker: escape untrusted cpu/gpu-model strings in the Rich-rendered hardware summary so markup-like content (e.g. "[/]") can't raise MarkupError and crash `comfy env` in pretty mode. - hardware(_detect_gpu_amd): return None (no phantom all-None AMD block) when nothing parses, matching the NVIDIA probes; gate the card loop on the "card" key prefix so a non-card metadata block isn't parsed as the GPU; exclude the "VRAM Total Used Memory" usage key so total capacity isn't understated. - hardware(_detect_gpu_nvidia_ctypes): pop/restore CUDA_VISIBLE_DEVICES around the ctypes probe (mirrors cuda_detect) so an exported ""/"-1" doesn't hide a present GPU. - tests: cover AMD total-vs-used key, metadata-block skip, all-None->None, and markup escaping. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Review resolution (5e5b4f4)Addressed the Cursor consolidated-panel findings: Fixed:
New tests cover each. Deferred to follow-ups (out of scope for this PR): 🟡 unbounded in-process ctypes CUDA hang (also affects CI note: the failing |
|
🤖 The reviews loop filed Linear follow-up ticket(s) for review thread(s) deferred as out of scope for this PR:
|
bigcat88
left a comment
There was a problem hiding this comment.
The feature itself checks out — I live-verified on a Linux box with an RTX 5090: comfy env --json reports the correct CPU (Ryzen 9 9950X), RAM (195 GB), and GPU (RTX 5090, 32 GB VRAM, via nvidia-smi), the payload validates against the schema, and 159/160 tests pass. One blocking test-hermeticity bug (inline) that makes the suite permanently red on any machine with a real NVIDIA GPU.
test_platform_calls_raising_do_not_escape patched the platform calls but left the real GPU probes live, so on a box with an actual GPU the unmocked _run executed nvidia-smi and the `gpu is None` assert failed (reproduced by review on an RTX 5090). Patch _run and _load_libcuda the same way the neighboring test does. Also merge main to pick up the uv.lock-pinned CI test deps (BE-3292) that fix the repo-wide tomlkit pytest break. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@comfy_cli/hardware.py`:
- Around line 200-215: Update the card-scanning loop in the AMD probe so it does
not unconditionally break after the first card-prefixed dictionary. Continue
scanning subsequent cards when the current card yields neither model nor
vram_bytes, and stop only once the probe has obtained relevant GPU data,
preserving the existing field parsing and invalid-value handling.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: e47c8044-09c0-48f1-b851-997678d865f6
📒 Files selected for processing (4)
comfy_cli/env_checker.pycomfy_cli/hardware.pycomfy_cli/schemas/env.jsontests/comfy_cli/test_hardware.py
A rocm-smi payload where card0 lacks the queried fields no longer masks a later card that has them; take the first card yielding any data. Per CodeRabbit review on #562. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
All review threads are now addressed and resolved (latest: CodeRabbit's AMD multi-card finding, fixed in 05588ad). Full suite green locally (2605 passed). Note on the red Windows Specific Commands check: it is a pre-existing repo-wide break, failing on every PR branch since ~Jul 18 — mixpanel 5.2.0 (unpinned) now pulls pydantic, whose |
|
🤖 The reviews loop filed Linear follow-up ticket(s) for review thread(s) deferred as out of scope for this PR:
|
ELI-5
comfy env --jsonnow tells you what machine you're on: your OS, chip, how muchRAM you have, and what GPU (and how much video memory) is available. Agents that
call the CLI can read this and avoid asking a weak laptop to run heavy local
image generation. It's purely additive — nothing that already reads the env
payload breaks.
What changed
comfy_cli/hardware.pywith one entry pointdetect_hardware() -> dictreturning
os / os_version / arch / cpu / ram_bytes / gpu. Thegpusub-block is{vendor, model, vram_bytes, unified_memory}ornull.cpufromsysctl -n machdep.cpu.brand_string(~0.012s). AppleSilicon (
arm64) →appleunified-memory GPU (RAM is the GPU budget). IntelMac →
unknownnon-unified GPU (we deliberately do not shell out tosystem_profilerper the ticket).nvidia-smi --query-gpu=name,memory.totalfirst, then actypes fallback via the existing
cuda_detect._load_libcuda(
cuInit/cuDeviceGet/cuDeviceGetName/cuDeviceTotalMem_v2).rocm-smi --showmeminfo vram --json; nulls acceptable.None), and every subprocess usestimeout=5.EnvChecker.fill_data()gains"hardware", andfill_print_table()gains aHardwarerow (cpu / RAM GB / GPU (VRAM GB or 'unified')).schemas/env.jsongains an optional, fully nullablehardwareproperty (
gpuis["object","null"]). Not added torequired, so older andfailed-probe payloads stay valid. Envelope schema unchanged (
envelope/1).Testing
tests/comfy_cli/test_hardware.py(new): macOS-arm64 apple/unified block;Intel-Mac unknown block; nvidia-smi happy path (
24564 MiB→ bytes); nvidia-smiabsent + libcuda ctypes fallback; every probe raising/timing out →
gpu: null,cpu: null, RAM still populated, no exception escapes;fill_data()includesthe key and the full payload validates against
schemas/env.json; nulled andhardware-absent payloads both still validate.
tests/comfy_cli/output/test_envelope_schemas.py::test_env_json_validates(real
comfy --json envsubprocess) passes → live payload validates and exits 0.ruff check+ruff format --checkclean.comfy env --jsonreportsDarwin / arm64 / Apple M4 Max / 64 GB+ apple unified GPU block, well under 1sadded latency.
Judgment calls
unified_memory false" and "gpu null if no GPU detected". I read these as: an
Intel Mac always has a GPU (integrated/AMD), just unidentifiable without the
forbidden
system_profiler, so it reports{vendor: "unknown", ..., unified_memory: false}rather than
null.nullis reserved for machines where no GPU is detected at all(e.g. a headless Linux CI runner). Flagging in case the reviewer prefers
null.cuda_detect: productioncuda_detectonlycalls
cuInit+cuDriverGetVersion; thecuDeviceGetName/cuDeviceTotalMem_v2calls here are new. Fully wrapped (worst case →
None), no subprocess, so a quirkydriver yields at most an odd model string, never a crash. I could not exercise it
against real NVIDIA hardware from this Mac; it's covered by a faithful ctypes mock.
gpu: nullmeans "not detected," not a user-facing dead-end — no "not supported"strings, no throw/deny path, no tests flipped to assert a dead-end. The falsification
trigger does not fire.