Skip to content

fix(local-inference): image-gen honors the probed GPU vendor instead of always CPU (#10727) - #11654

Merged
lalalune merged 2 commits into
developfrom
fix/10727-gpu-probe-honesty
Jul 2, 2026
Merged

lalalune merged 2 commits into
developfrom
fix/10727-gpu-probe-honesty

Conversation

@lalalune

@lalalune lalalune commented Jul 2, 2026

Copy link
Copy Markdown
Member

Summary

Closes the one remaining code-side silent-CPU-fallback in local inference that #10727's audit surfaced beyond the already-merged embedding-probe flip (#10812): image generation ignored the GPU entirely.

LocalInferenceService.loadImageGenBackend hardcoded gpu: undefined in the ImageGenRuntimeProfile, so selectImageGenBackends fell through to sd-cpp CPU on every Linux/Windows box — including NVIDIA, whose backend probeHardware already detects reliably via nvidia-smi (backend: "cuda"). An accelerated path was available and never chosen — exactly the fallback #10727 says to eliminate.

What changed

  • imagegen/backend-selector.ts — new pure imageGenGpuVendorFromProbeBackend (cuda→nvidia, metal→apple, vulkan→amd, null→undefined).
  • service.ts — thread the real probe vendor into the profile via a detectImageGenGpuVendor() helper; NVIDIA Linux/Windows now reaches the CUDA/TensorRT path. A probe failure degrades gracefully to the platform default with a logged reason (not a silent swallow), and image-gen never crashes on a probe error.
  • ensure-local-inference-handler.ts (SEV-4) — the embedding handler's swallowed probeHardware().catch(() => undefined) now logs why the probe failed, so a broken probe on an accelerated box is visible.
  • hardware.ts (SEV-3) — corrected two false comments that claimed the probe uses capacitor-llama and reports AMD as vulkan; it does neither (nvidia-smi + Apple-Silicon detection; AMD/Intel left null at probe).

Evidence (macOS M4 Max, develop worktree)

  • Tests: imagegen/backend-selector.test.ts + hardware.test.ts26 pass. New tests drive the real mapper the caller uses (not synthetic gpu:"nvidia" profiles, the gap the audit called out): assert NVIDIA→CUDA at the head of the try-list, win32→TensorRT, and that macOS (mflux/Metal) + AMD/Intel-null paths are unchanged.
  • Typecheck: tsc -p plugins/plugin-local-inference — 0 errors in changed files (satisfies ImageGenRuntimeProfile compiles).
  • Lint: biome clean.
  • Reviewed by a 5-lens adversarial pass (correctness / regression / test-integrity / completeness / architecture).

Deliberately deferred (device-gated, not shipped blind)

Embeddings/image-gen on AMD/Intel still run CPU because probeHardware leaves them null at probe time — no cheap pre-load VRAM query, and guessing vulkan from a macOS host that can't verify it risks a hard GPU-open throw (there is no TS-side CPU retry). This is documented in-code and belongs on a real AMD/Intel-GPU host (cf. the needs-human #11339 pattern for the NVIDIA/CUDA validation of #10812). The image-gen path already routes amd/intel to Vulkan the moment the probe can report it.

Refs #10727.

…of always CPU (#10727)

The image-gen loader hardcoded `gpu: undefined` in the ImageGenRuntimeProfile,
so selectImageGenBackends fell through to sd-cpp CPU on every Linux/Windows box
— even NVIDIA, whose backend probeHardware reliably detects via nvidia-smi. A
silent CPU fallback with an accelerated path available (the #10727 rule).

- Add pure imageGenGpuVendorFromProbeBackend (cuda->nvidia, metal->apple,
  vulkan->amd, null->undefined) and thread the real probe vendor into the
  profile; NVIDIA Linux/Windows now reaches the CUDA/TensorRT path. Probe
  failure degrades gracefully to the platform default with a logged reason
  (no silent swallow).
- SEV-4: the embedding handler's swallowed `probeHardware().catch(() =>
  undefined)` now logs why, so a broken probe on an accelerated box is visible.
- SEV-3: correct two false hardware.ts comments (claimed the probe uses
  capacitor-llama and reports AMD as vulkan — it does neither; it uses
  nvidia-smi + Apple-Silicon detection and leaves AMD/Intel null at probe).
- Tests exercise the REAL mapper the caller uses (not synthetic gpu profiles),
  asserting NVIDIA reaches CUDA and macOS/AMD paths are unchanged.

Known, deliberately deferred: embeddings/image-gen on AMD/Intel still run CPU
because probeHardware leaves them null at probe time (no cheap pre-load VRAM
query; guessing vulkan risks a hard GPU-open throw with no CPU retry). Routed to
a real-GPU-host follow-up rather than shipped blind from a macOS host.

Refs #10727.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ca908382-410d-41e5-8c5b-1d339a4e50dd

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/10727-gpu-probe-honesty

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@lalalune

lalalune commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

Reviewed and updated this PR.

Decision: keep #10727 open as the broader local-model lifecycle epic, but this code-side slice is correct to land. The implementation only threads facts the existing probe can honestly know: CUDA -> NVIDIA, Metal -> Apple, and unknown/null remains the platform default. It deliberately does not claim AMD/Intel Vulkan until the probe can prove it.

I added .github/issue-evidence/10727-imagegen-gpu-probe-honesty.md so the branch records the scope, verification, and N/A evidence rows for real-device matrix/screenshots.

Local verification on 039a5b8889:

  • bun run --cwd plugins/plugin-local-inference test -- src/services/imagegen/backend-selector.test.ts src/services/hardware.test.ts -> 2 files / 26 tests passed
  • bun run --cwd plugins/plugin-local-inference typecheck -> passed
  • bun run --cwd plugins/plugin-local-inference lint:check src/services/imagegen/backend-selector.ts src/services/imagegen/backend-selector.test.ts src/services/imagegen/index.ts src/services/service.ts src/services/hardware.ts src/runtime/ensure-local-inference-handler.ts -> passed
  • git diff --check origin/develop...HEAD and git diff --check -> passed

CI is queued on the new commit; I am enabling auto-merge rather than merging ahead of it.

@lalalune
lalalune merged commit 33b027f into develop Jul 2, 2026
30 of 38 checks passed
@lalalune
lalalune deleted the fix/10727-gpu-probe-honesty branch July 2, 2026 23:03
lalalune added a commit that referenced this pull request Jul 2, 2026
… loader's capability gate (#10727) (#11671)

Follow-up to the merged #10727 image-gen vendor-threading fix (#11654), which
only genuinely helped Windows NVIDIA. A 5-lens adversarial review caught that on
Linux+NVIDIA the fix was still a no-op: selectImageGenBackends gated the CUDA
head on `profile.sdCpp?.cudaCapable`, positive evidence the real caller never
populates, so a Linux NVIDIA box still returned [{sd-cpp, cpu}] — byte-identical
to the pre-fix output — and silently ran image-gen on CPU (the primary #10727
target).

- Linux+NVIDIA now proposes CUDA first and lets loadSdCppImageGenBackend be the
  single source of capability truth (it probes the binary and throws
  ImageGenBackendUnavailableError → clean CPU fall-through when CUDA is
  unproven). Only demote to CPU-only on explicit evidence the binary CANNOT do
  CUDA. Same trust-the-loader contract win32 and the AMD/Intel branch already use.
- Log each accelerated→next image-gen fall-through so a GPU box degrading to CPU
  is visible, not silent — the #10727 failure mode one layer below selection.
- Correct the SEV-4 embedding probe-failure warn: the fallback is the
  performance preset (gpuLayers auto), not a 'conservative default'.
- Tests: assert CUDA-first on the EXACT real-caller profile shape (no synthetic
  sdCpp — the shape the merged test masked with an injected cudaCapable flag),
  add a mocked-probe service seam guarding the wiring, and prove macOS is
  unaffected.

Refs #10727.

Co-authored-by: Shaw <shawgotbags@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


I'll analyze this and get back to you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants