fix(ai-check): use canonical GPU detection

This commit is contained in:
signerless 2026-08-28 15:35:48 +02:00
parent 7ff6aa0d19
commit 6fb813af65
3 changed files with 150 additions and 6 deletions

View file

@ -6,6 +6,7 @@
*/
const DeterministicModelSelector = require('./deterministic-selector');
const HardwareDetector = require('../hardware/detector');
const { OllamaNativeScraper } = require('../ollama/native-scraper');
const OllamaClient = require('../ollama/client');
const crypto = require('crypto');
@ -14,10 +15,11 @@ const path = require('path');
const { evaluateFineTuningSupport } = require('./fine-tuning-support');
class AICheckSelector {
constructor() {
this.deterministicSelector = new DeterministicModelSelector();
this.ollamaClient = new OllamaClient();
this.ollamaScraper = new OllamaNativeScraper();
constructor(options = {}) {
this.deterministicSelector = options.deterministicSelector || new DeterministicModelSelector();
this.hardwareDetector = options.hardwareDetector || new HardwareDetector();
this.ollamaClient = options.ollamaClient || new OllamaClient();
this.ollamaScraper = options.ollamaScraper || new OllamaNativeScraper();
this.cachePath = path.join(require('os').homedir(), '.llm-checker', 'ai-check-cache.json');
// Priority models for evaluation (prefer these if installed)
@ -81,6 +83,40 @@ Respond with JSON only, no additional text.`;
);
}
/**
* Use the same hardware detector as `check` and `hw-detect`, then translate
* its richer result into the deterministic selector's input shape.
*
* Previously AI Check called DeterministicModelSelector#getHardware(), whose
* intentionally minimal non-macOS fallback always returned `cpu_only`. That
* discarded GPUs which the unified detector had already found (notably the
* Windows RX 7900 XTX reported in issue #106).
*/
async getDetectedHardwareProfile() {
const detected = await this.hardwareDetector.getSystemInfo();
const summary = detected?.summary || {};
const bestBackend = String(summary.bestBackend || '').toLowerCase();
const runtimeBackend = String(summary.runtimeBackend || '').toLowerCase();
const normalized = this.deterministicSelector.normalizeHardwareProfile({
...detected,
acceleration: {
supports_metal: bestBackend === 'metal' || runtimeBackend === 'metal',
supports_cuda: bestBackend === 'cuda' || runtimeBackend === 'cuda',
supports_rocm: bestBackend === 'rocm' || runtimeBackend === 'rocm',
supports_vulkan: runtimeBackend === 'vulkan'
}
});
return {
...normalized,
acceleration: {
...normalized.acceleration,
supports_vulkan: runtimeBackend === 'vulkan'
}
};
}
async aiCheck(options = {}) {
const {
category = 'general',
@ -93,8 +129,9 @@ Respond with JSON only, no additional text.`;
const chalk = require('chalk');
// Phase 1: Get ALL available models from the 177-model Ollama database
const hardware = await this.deterministicSelector.getHardware();
// Phase 1: Detect hardware through the canonical detector used by the
// rest of the CLI, then load all available models.
const hardware = await this.getDetectedHardwareProfile();
// Use the same synced database that recommend/check use.
const ollamaData = await this.loadModelDatabase();

View file

@ -0,0 +1,106 @@
const assert = require('assert');
const AICheckSelector = require('../src/models/ai-check-selector');
async function testAiCheckUsesCanonicalDiscreteGpuDetection() {
const detectedHardware = {
cpu: {
brand: 'AMD Ryzen 7 9800X3D 8-Core Processor',
architecture: 'x86_64',
cores: 16,
physicalCores: 8
},
memory: { total: 32 },
gpu: {
model: 'AMD Radeon RX 7900 XTX',
vendor: 'AMD',
vram: 24,
vramPerGPU: 24,
gpuCount: 1,
dedicated: true,
all: [
{
model: 'AMD Radeon RX 7900 XTX',
vendor: 'AMD',
vram: 24
}
]
},
summary: {
bestBackend: 'cpu',
runtimeBackend: 'cpu',
totalVRAM: 24,
hasDedicatedGPU: true,
hasIntegratedGPU: false
},
os: { platform: 'win32' }
};
let detectorCalls = 0;
const selector = new AICheckSelector({
hardwareDetector: {
async getSystemInfo() {
detectorCalls += 1;
return detectedHardware;
}
}
});
const hardware = await selector.getDetectedHardwareProfile();
assert.strictEqual(detectorCalls, 1, 'AI Check should call the canonical hardware detector');
assert.strictEqual(hardware.gpu.type, 'amd', 'the detected Radeon must not collapse to cpu_only');
assert.strictEqual(hardware.gpu.vramGB, 24, 'the detected 24GB VRAM budget must be preserved');
assert.strictEqual(hardware.gpu.gpuCount, 1, 'virtual adapters must not reappear as extra GPUs');
assert.strictEqual(hardware.acceleration.supports_rocm, false, 'inventory detection must not claim an unconfirmed ROCm runtime');
}
async function testAiCheckPreservesConfirmedVulkanAssist() {
const selector = new AICheckSelector({
hardwareDetector: {
async getSystemInfo() {
return {
cpu: { brand: 'AMD Ryzen AI 9', architecture: 'x86_64', cores: 24 },
memory: { total: 64 },
gpu: {
model: 'AMD Radeon 890M Graphics',
vendor: 'AMD',
vram: 32,
sharedMemory: 32,
dedicated: false,
gpuCount: 1
},
summary: {
bestBackend: 'cpu',
runtimeBackend: 'vulkan',
hasIntegratedGPU: true,
hasDedicatedGPU: false
},
os: { platform: 'win32' }
};
}
}
});
const hardware = await selector.getDetectedHardwareProfile();
assert.strictEqual(hardware.gpu.type, 'amd');
assert.strictEqual(hardware.acceleration.supports_vulkan, true);
assert.strictEqual(hardware.acceleration.supports_rocm, false);
}
async function run() {
await testAiCheckUsesCanonicalDiscreteGpuDetection();
await testAiCheckPreservesConfirmedVulkanAssist();
console.log('ai-check-hardware-detection.test.js: OK');
}
if (require.main === module) {
run().catch((error) => {
console.error('ai-check-hardware-detection.test.js: FAILED');
console.error(error);
process.exit(1);
});
}
module.exports = { run };

View file

@ -16,6 +16,7 @@ const TESTS = [
{ name: 'High-end / multi-GPU VRAM detection', file: 'hardware-vram-highend.test.js', category: 'Hardware' },
{ name: 'CPU detector Windows fallback', file: 'cpu-detector-windows-fallback.test.js', category: 'Hardware' },
{ name: 'Virtual-monitor GPU detection', file: 'virtual-monitor-gpu-detection.test.js', category: 'Hardware' },
{ name: 'AI Check hardware detection', file: 'ai-check-hardware-detection.test.js', category: 'Hardware' },
{ name: 'Termux platform support', file: 'termux-platform-support.test.js', category: 'Hardware' },
{ name: 'Token speed estimation', file: 'token-speed-estimation.test.js', category: 'Performance' },
{ name: 'Deterministic model pool', file: 'deterministic-model-pool-check.js', category: 'Recommendations' },