Repository navigation
fix(platform): detect legacy CPU incompatibility before Antigravity migration prompt (#27342) - #29426
dylanyunlon wants to merge 1 commit into
Conversation
…igration prompt (google-gemini#27342) ## Summary This PR addresses an issue where users with legacy CPUs (e.g. AMD A-Series/Llano, Intel Core 2 Duo) that lack AVX/AVX2 instruction sets are shown the Antigravity CLI installation command, even though the Go-based binary will crash immediately with SIGILL (exit code 132) on their hardware. By adding runtime CPU feature detection and integrating it into the migration banner, help command, and telemetry pipeline, we ensure that: 1. Users on incompatible hardware see a clear warning instead of an install command that leads to a crash. 2. The Gemini team can track how many active users have legacy CPUs via telemetry to plan baseline x86-64-v1 builds. ## Details 1. **CPU Feature Detection:** New `cpuCompatibility.ts` service in `packages/core` reads /proc/cpuinfo (Linux), queries sysctl (macOS), or applies model-string heuristics (Windows) to detect SSE4.2, AVX, AVX2, and AES-NI support. Determines x86-64 microarchitecture level (v1/v2/v3/v4) and compatibility with GOAMD64=v3 binaries. 2. **Platform Diagnostics:** New `platformDiagnostics.ts` service provides a cached, process-lifetime compatibility check and a formatted diagnostics report for bug reports and /stats output. 3. **Banner Suppression:** `useBanner.ts` now calls `getAntigravityCompatibility()`, on incompatible CPUs, the install command is replaced with a yellow warning explaining the hardware limitation and directing users to continue with Gemini CLI (Node.js). 4. **Help Command:** `helpCommand.ts` checks CPU compatibility when users query `/help install antigravity` or `/help antigravity cpu`. Incompatible systems see the hardware warning with a link to google-gemini#27342. 5. **Telemetry Enrichment:** Three new EventMetadataKeys (203–205) added to clearcut-logger START_SESSION events: CPU_MICROARCH_LEVEL, CPU_ANTIGRAVITY_COMPAT, CPU_MISSING_FEATURES. 6. **Gateway Auth:** Fixed `validateAuthMethod` to recognize the GATEWAY auth type triggered by GOOGLE_GEMINI_BASE_URL. 7. **Automated Verification:** - 24 unit tests in cpuCompatibility.test.ts covering Linux /proc/cpuinfo parsing (including AMD A6-3420M from the original issue), macOS sysctl, Windows model heuristics, ARM passthrough, and edge cases. - 6 unit tests in platformDiagnostics.test.ts for caching, report building, and formatting. - Updated tests in antigravityUtils, useBanner, and helpCommand with mock-based CPU compatibility injection. ## Related Issues Resolves google-gemini#27342, Compatibility Issue: Antigravity CLI requires AVX instructions missing on legacy CPUs (AMD A-Series) ## How to Validate 1. Run the CPU compatibility test suite: ```bash npm test -w @google/gemini-cli-core -- src/services/cpuCompatibility.test.ts --run ``` 2. Run the platform diagnostics test suite: ```bash npm test -w @google/gemini-cli-core -- src/services/platformDiagnostics.test.ts --run ``` 3. Run the CLI banner and help command tests: ```bash npm test -w @google/gemini-cli -- src/ui/hooks/useBanner.test.ts --run npm test -w @google/gemini-cli -- src/ui/commands/helpCommand.test.ts --run npm test -w @google/gemini-cli -- src/ui/utils/antigravityUtils.test.ts --run ``` 4. Run project-wide linting and type checking: ```bash npm run build ``` ## Pre-Merge Checklist - [ ] Updated relevant documentation and README (if needed) - [x] Added/updated tests (if needed) - [ ] Noted breaking changes (if any) - [x] Validated on required platforms/methods: - [x] Linux - [x] npm run
|
📊 PR Size: size/XL
|
|
You already have 7 pull requests open. Please work on getting existing PRs merged before opening more. |
|
/gemini review |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces runtime CPU feature detection to prevent users with legacy hardware from attempting to install the Antigravity CLI, which requires AVX/AVX2 instruction sets. By proactively identifying incompatible systems, the CLI now provides clear warnings instead of failing with a crash, while also enriching telemetry data to better inform future development and support for older CPU architectures. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces CPU compatibility detection and platform diagnostics to ensure the host system meets the hardware requirements (specifically x86-64-v3 / AVX2) of the Go-based Antigravity CLI binary, preventing SIGILL crashes on legacy CPUs. It adds compatibility checks in the help command, banner hooks, and telemetry, along with comprehensive unit tests. The review feedback suggests implementing the environment variable bypass GEMINI_CPU_COMPAT_SKIP in the production code to allow skipping compatibility checks, and using optional chaining with trimming when parsing CPU model strings to prevent potential runtime errors.
Note: Security Review did not run due to the size of the PR.
| export function checkCpuCompatibility(): CpuCompatibilityResult { | ||
| const cpus = os.cpus(); |
There was a problem hiding this comment.
The environment variable GEMINI_CPU_COMPAT_SKIP was added to the TestRig clean environment list in packages/test-utils/src/test-rig.ts, but its handling is not implemented in the production code. This means the bypass flag has no effect. Please implement the check at the beginning of checkCpuCompatibility to allow skipping the compatibility check when the environment variable is set.
export function checkCpuCompatibility(): CpuCompatibilityResult {
if (process.env['GEMINI_CPU_COMPAT_SKIP'] === '1' || process.env['GEMINI_CPU_COMPAT_SKIP'] === 'true') {
return {
compatible: true,
cpuModel: 'Skipped via env',
arch: process.arch,
microarchLevel: 'unknown',
features: { sse42: true, avx: true, avx2: true, aesni: true },
missingFeatures: [],
};
}
const cpus = os.cpus();| return { sse42: false, avx: false, avx2: false, aesni: false }; | ||
| } | ||
|
|
||
| const model = cpus[0].model.toLowerCase(); |
There was a problem hiding this comment.
To prevent potential runtime TypeErrors if cpus[0] or cpus[0].model is undefined, use optional chaining. Additionally, when using an optional string with a fallback value, trim the optional string and use the fallback if the result is empty to avoid uninformative messages from whitespace-only strings.
| const model = cpus[0].model.toLowerCase(); | |
| const model = cpus[0]?.model?.trim().toLowerCase() || ''; |
References
- When using an optional string with a fallback value, trim the optional string and use the fallback if the result is empty to avoid uninformative messages from whitespace-only strings.
- When consuming an object, if a property is optional in its type definition (interface), callers must handle the
undefinedcase (e.g., by providing a default with??). Do not rely on the implementation details of the function that creates the object to always provide a value, as this can change. Code against the interface contract.
There was a problem hiding this comment.
Code Review
This pull request introduces CPU compatibility detection and platform diagnostics to warn users if their hardware lacks the required instruction sets (AVX/AVX2, SSE4.2) to run the Go-based Antigravity CLI binary, preventing SIGILL crashes. It integrates these checks into the CLI banner, help commands, and telemetry tracking, and updates gateway authentication validation. The reviewer's feedback focuses on making the CPU feature detection more robust by handling failures gracefully and failing-safe (assuming compatibility) to avoid false-positive warnings on modern CPUs in restricted environments. Additionally, the reviewer highlights a violation of the repository's rule against using module-level global variables for state caching in platformDiagnostics.ts.
| export function detectCpuFeatures(): CpuFeatureFlags { | ||
| const defaultFlags: CpuFeatureFlags = { | ||
| sse42: false, | ||
| avx: false, | ||
| avx2: false, | ||
| aesni: false, | ||
| }; | ||
|
|
||
| try { | ||
| if (process.platform === 'linux') { | ||
| return detectCpuFeaturesLinux(); | ||
| } else if (process.platform === 'darwin') { | ||
| return detectCpuFeaturesDarwin(); | ||
| } else if (process.platform === 'win32') { | ||
| return detectCpuFeaturesWindows(); | ||
| } | ||
| } catch (error) { | ||
| debugLogger.debug( | ||
| `Failed to detect CPU features: ${error instanceof Error ? error.message : String(error)}`, | ||
| ); | ||
| } | ||
|
|
||
| return defaultFlags; | ||
| } |
There was a problem hiding this comment.
If CPU feature detection fails or is inconclusive (e.g., due to permission issues, sandboxing, or restricted environments), returning all-false default flags will cause modern CPUs to be falsely reported as incompatible. Returning null allows the caller to handle inconclusive detection with a fail-safe default (assuming compatibility).
export function detectCpuFeatures(): CpuFeatureFlags | null {
try {
if (process.platform === 'linux') {
return detectCpuFeaturesLinux();
} else if (process.platform === 'darwin') {
return detectCpuFeaturesDarwin();
} else if (process.platform === 'win32') {
return detectCpuFeaturesWindows();
}
} catch (error) {
debugLogger.debug(
`Failed to detect CPU features: ${error instanceof Error ? error.message : String(error)}`
);
}
return null;
}| if (!flagsLine) { | ||
| return { sse42: false, avx: false, avx2: false, aesni: false }; | ||
| } |
There was a problem hiding this comment.
If the flags line is missing in /proc/cpuinfo, returning all-false flags will cause a false-positive incompatibility warning. Throwing an error allows the caller to treat this as an inconclusive detection and fail-safe.
| if (!flagsLine) { | |
| return { sse42: false, avx: false, avx2: false, aesni: false }; | |
| } | |
| if (!flagsLine) { | |
| throw new Error('No flags line found in /proc/cpuinfo'); | |
| } |
| function detectCpuFeaturesDarwin(): CpuFeatureFlags { | ||
| const query = (key: string): boolean => { | ||
| try { | ||
| const output = execFileSync('sysctl', ['-n', key], { | ||
| encoding: 'utf-8', | ||
| timeout: 5000, | ||
| }).trim(); | ||
| return output === '1'; | ||
| } catch { | ||
| return false; | ||
| } | ||
| }; | ||
|
|
||
| return { | ||
| sse42: query('hw.optional.sse4_2'), | ||
| avx: query('hw.optional.avx1_0'), | ||
| avx2: query('hw.optional.avx2_0'), | ||
| aesni: query('hw.optional.aes'), | ||
| }; | ||
| } |
There was a problem hiding this comment.
If sysctl queries fail completely (e.g., command not found or permission denied), returning all-false flags will cause a false-positive incompatibility warning on macOS. Tracking query success and throwing an error allows the caller to fail-safe.
function detectCpuFeaturesDarwin(): CpuFeatureFlags {
let success = false;
const query = (key: string): boolean => {
try {
const output = execFileSync('sysctl', ['-n', key], {
encoding: 'utf-8',
timeout: 5000,
}).trim();
success = true;
return output === '1';
} catch {
return false;
}
};
const features = {
sse42: query('hw.optional.sse4_2'),
avx: query('hw.optional.avx1_0'),
avx2: query('hw.optional.avx2_0'),
aesni: query('hw.optional.aes'),
};
if (!success) {
throw new Error('sysctl queries failed');
}
return features;
}| if (!cpus || cpus.length === 0) { | ||
| return { sse42: false, avx: false, avx2: false, aesni: false }; | ||
| } |
There was a problem hiding this comment.
If os.cpus() returns empty or invalid data, throwing an error allows the caller to treat this as inconclusive and fail-safe.
| if (!cpus || cpus.length === 0) { | |
| return { sse42: false, avx: false, avx2: false, aesni: false }; | |
| } | |
| if (!cpus || cpus.length === 0) { | |
| throw new Error('os.cpus() returned empty or invalid data'); | |
| } |
| export function checkCpuCompatibility(): CpuCompatibilityResult { | ||
| const cpus = os.cpus(); | ||
| const cpuModel = cpus && cpus.length > 0 ? cpus[0].model : 'Unknown'; | ||
| const arch = process.arch; | ||
| const features = detectCpuFeatures(); | ||
| const microarchLevel = getMicroarchLevel(features); | ||
|
|
||
| const missingFeatures: string[] = []; | ||
| for (const feature of REQUIRED_FEATURES) { | ||
| if (!features[feature]) { | ||
| missingFeatures.push(feature.toUpperCase()); | ||
| } | ||
| } | ||
|
|
||
| // Non-x86 architectures (ARM, etc.) are always considered compatible | ||
| // because Antigravity provides separate binaries for those platforms. | ||
| const isNonX86 = arch !== 'x64' && arch !== 'ia32'; | ||
| const compatible = isNonX86 || missingFeatures.length === 0; | ||
|
|
||
| return { | ||
| compatible, | ||
| cpuModel, | ||
| arch, | ||
| microarchLevel, | ||
| features, | ||
| missingFeatures, | ||
| }; | ||
| } |
There was a problem hiding this comment.
Handle the case where detectCpuFeatures() returns null (inconclusive detection) by failing-safe and assuming compatibility, preventing false-positive warnings on modern CPUs in restricted environments.
export function checkCpuCompatibility(): CpuCompatibilityResult {
const cpus = os.cpus();
const cpuModel = cpus && cpus.length > 0 ? cpus[0].model : 'Unknown';
const arch = process.arch;
const features = detectCpuFeatures();
if (!features) {
return {
compatible: true,
cpuModel,
arch,
microarchLevel: 'unknown',
features: { sse42: true, avx: true, avx2: true, aesni: true },
missingFeatures: [],
};
}
const microarchLevel = getMicroarchLevel(features);
const missingFeatures: string[] = [];
for (const feature of REQUIRED_FEATURES) {
if (!features[feature]) {
missingFeatures.push(feature.toUpperCase());
}
}
// Non-x86 architectures (ARM, etc.) are always considered compatible
// because Antigravity provides separate binaries for those platforms.
const isNonX86 = arch !== 'x64' && arch !== 'ia32';
const compatible = isNonX86 || missingFeatures.length === 0;
return {
compatible,
cpuModel,
arch,
microarchLevel,
features,
missingFeatures,
};
}| * Cached compatibility result to avoid redundant /proc/cpuinfo reads or | ||
| * sysctl invocations within the same process lifetime. | ||
| */ | ||
| let cachedCompatibility: CpuCompatibilityResult | null = null; |
There was a problem hiding this comment.
This module-level global variable cachedCompatibility is used as a cache, which violates the repository's general rule: 'Avoid module-level global variables for state like caches to prevent race conditions and memory issues in concurrent environments. Instead, use session-scoped or instance-scoped state and leverage standard cache implementations like LRUCache.' Consider refactoring this to use session-scoped or instance-scoped state, or leverage a standard cache implementation.
References
- Avoid module-level global variables for state like caches to prevent race conditions and memory issues in concurrent environments. Instead, use session-scoped or instance-scoped state and leverage standard cache implementations like LRUCache.
Summary
This PR addresses an issue where users with legacy CPUs (e.g. AMD
A-Series/Llano, Intel Core 2 Duo) that lack AVX/AVX2 instruction sets
are shown the Antigravity CLI installation command, even though the
Go-based binary will crash immediately with SIGILL (exit code 132) on
their hardware.
By adding runtime CPU feature detection and integrating it into the
migration banner, help command, and telemetry pipeline, we ensure that:
install command that leads to a crash.
via telemetry to plan baseline x86-64-v1 builds.
Details
CPU Feature Detection: New
cpuCompatibility.tsservice inpackages/corereads /proc/cpuinfo (Linux), queries sysctl (macOS),or applies model-string heuristics (Windows) to detect SSE4.2, AVX,
AVX2, and AES-NI support. Determines x86-64 microarchitecture level
(v1/v2/v3/v4) and compatibility with GOAMD64=v3 binaries.
Platform Diagnostics: New
platformDiagnostics.tsserviceprovides a cached, process-lifetime compatibility check and a
formatted diagnostics report for bug reports and /stats output.
Banner Suppression:
useBanner.tsnow callsgetAntigravityCompatibility(), on incompatible CPUs, the installcommand is replaced with a yellow warning explaining the hardware
limitation and directing users to continue with Gemini CLI (Node.js).
Help Command:
helpCommand.tschecks CPU compatibility whenusers query
/help install antigravityor/help antigravity cpu.Incompatible systems see the hardware warning with a link to Compatibility Issue: Antigravity CLI requires AVX instructions missing on legacy CPUs (AMD A-Series) #27342.
Telemetry Enrichment: Three new EventMetadataKeys (203–205)
added to clearcut-logger START_SESSION events:
CPU_MICROARCH_LEVEL, CPU_ANTIGRAVITY_COMPAT, CPU_MISSING_FEATURES.
Gateway Auth: Fixed
validateAuthMethodto recognize theGATEWAY auth type triggered by GOOGLE_GEMINI_BASE_URL.
Automated Verification:
/proc/cpuinfo parsing (including AMD A6-3420M from the original
issue), macOS sysctl, Windows model heuristics, ARM passthrough,
and edge cases.
report building, and formatting.
with mock-based CPU compatibility injection.
Related Issues
Resolves #27342, Compatibility Issue: Antigravity CLI requires AVX
instructions missing on legacy CPUs (AMD A-Series)
How to Validate
npm test -w @google/gemini-cli-core -- src/services/cpuCompatibility.test.ts --runnpm test -w @google/gemini-cli-core -- src/services/platformDiagnostics.test.ts --runPre-Merge Checklist