Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions packages/app/src/components/inference/ui/ScatterGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ import {
renderKnownIssueAnnotations,
} from '@/components/inference/utils/knownIssueAnnotations';
import { matchesQuickFilters } from '@/components/inference/utils/quickFilters';
import { changelogConfigToHwKey } from '@/components/inference/utils/changelogFormatters';

// Greedy label-collision avoidance.
// Each candidate is the y-position of the FIRST baseline (relative to point
Expand Down Expand Up @@ -634,16 +635,17 @@ const ScatterGraph = React.memo(

// --- Changelog ---
const changelog = availableRuns ? availableRuns[selectedRunId]?.changelog || null : null;
const highlightConfigSuffixes = useMemo(() => {
const highlightedHwKeys = useMemo(() => {
if (availableRuns) {
const cl = availableRuns[selectedRunId]?.changelog;
if (cl) {
const suffixes = cl.entries.flatMap((entry: any) =>
const hwKeys = cl.entries.flatMap((entry: any) =>
(entry.config_keys ?? entry['config-keys'] ?? [])
.filter((key: string) => selectedPrecisions.includes(key.split('-')[1]))
.map((key: string) => key.split('-').slice(2).join('-')),
.map(changelogConfigToHwKey)
.filter((key: string | null): key is string => key !== null),
);
return new Set(suffixes);
return new Set(hwKeys);
}
}
return new Set<string>();
Expand Down Expand Up @@ -2913,7 +2915,7 @@ const ScatterGraph = React.memo(
label: getDisplayLabel(hwConfig),
color: resolveColor(key),
title: hwConfig.gpu,
isHighlighted: highlightConfigSuffixes.has(key.replaceAll('_', '-')),
isHighlighted: highlightedHwKeys.has(key),
hw: key,
isActive: showAllHardwareTypes ? true : effectiveOfficialHwTypes.has(key),
onClick: showAllHardwareTypes
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { describe, expect, it } from 'vitest';

import { configKeyMatchesHwKey, formatConfigKeys } from './changelogFormatters';
import {
changelogConfigToHwKey,
configKeyMatchesHwKey,
formatConfigKeys,
} from './changelogFormatters';

describe('formatConfigKeys', () => {
it('formats a standard config key', () => {
Expand Down Expand Up @@ -43,6 +47,26 @@ describe('formatConfigKeys', () => {
expect(result).toContain('TRTLLM');
expect(result).toContain('FP4');
});

it('uses the legend framework label for an agentic HiCache config', () => {
expect(formatConfigKeys('dsv4-fp4-mi355x-mori-sglang-agentic-hicache')).toBe(
'MI355X (MoRI SGLang) DeepSeek-V4-Pro FP4',
);
});
});

describe('changelogConfigToHwKey', () => {
it('strips agentic scenario and cache-backend suffixes from the legend identity', () => {
expect(changelogConfigToHwKey('dsv4-fp4-mi355x-mori-sglang-agentic-hicache')).toBe(
'mi355x_mori-sglang',
);
});

it('keeps a trailing MTP spec method while dropping agentic metadata', () => {
expect(changelogConfigToHwKey('dsv4-fp4-mi355x-sglang-agentic-hicache-mtp')).toBe(
'mi355x_sglang_mtp',
);
});
});

describe('configKeyMatchesHwKey', () => {
Expand All @@ -68,6 +92,12 @@ describe('configKeyMatchesHwKey', () => {
expect(configKeyMatchesHwKey('dsr1-fp8-mi355x-sglang-disagg', 'mi355x_mori-sglang')).toBe(true);
});

it('matches an agentic HiCache changelog key to the framework-only legend key', () => {
expect(
configKeyMatchesHwKey('dsv4-fp4-mi355x-mori-sglang-agentic-hicache', 'mi355x_mori-sglang'),
).toBe(true);
});

it('matches sglang framework', () => {
expect(configKeyMatchesHwKey('gptoss-fp8-mi300x-sglang', 'mi300x_sglang')).toBe(true);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,40 @@
import {
resolveFrameworkAliasesInString,
FRAMEWORK_ALIASES,
FW_REGISTRY,
resolveFrameworkAlias,
resolveFrameworkPartLabel,
} from '@semianalysisai/inferencex-constants';

import { type Precision, MODEL_PREFIX_MAPPING, getPrecisionLabel } from '@/lib/data-mappings';
import { getFrameworkLabel } from '@/lib/utils';
import { getHardwareConfig } from '@/lib/constants';
import { getDisplayLabel } from '@/lib/utils';

const CHANGELOG_FRAMEWORK_KEYS = [
...Object.keys(FW_REGISTRY),
...Object.keys(FRAMEWORK_ALIASES),
].toSorted((a, b) => b.length - a.length);

/**
* Convert a changelog config key into the canonical hardware key used by chart
* points and the legend. Agentic config keys append scenario details such as
* `agentic`, `hicache`, and `pcp` after the serving framework; those are not
* framework labels and must not become part of the legend identity.
*/
export function changelogConfigToHwKey(configKey: string): string | null {
const parts = configKey.toLowerCase().split('-');
const gpu = parts[2];
const remainder = parts.slice(3).join('-');
if (!gpu || !remainder) return null;

const framework = CHANGELOG_FRAMEWORK_KEYS.find(
(candidate) => remainder === candidate || remainder.startsWith(`${candidate}-`),
);
if (!framework) return null;

const trailingParts = remainder.slice(framework.length).split('-').filter(Boolean);
const specSuffix = trailingParts.includes('mtp') ? '_mtp' : '';
return `${gpu}_${resolveFrameworkAlias(framework)}${specSuffix}`;
}

export function formatChangelogDescription(desc: string | string[]) {
if (typeof desc === 'string') {
Expand Down Expand Up @@ -33,23 +63,26 @@ export function formatChangelogDescription(desc: string | string[]) {
* Normalizes both to hyphen-separated form for comparison.
*/
export function configKeyMatchesHwKey(configKey: string, hwKey: string): boolean {
const gpuAndFramework = resolveFrameworkAliasesInString(configKey.split('-').slice(2).join('-'));
const normalizedHwKey = hwKey.replaceAll('_', '-');
return gpuAndFramework === normalizedHwKey;
return changelogConfigToHwKey(configKey) === hwKey;
}

export function formatConfigKeys(key: string) {
const parts = key.split('-');
const model = parts[0];
const precision = parts[1];
const gpu = parts[2];
const framework = parts.slice(3).join('-');
// Strip -mtp suffix before lookup; MTP is shown separately
const isMtp = framework.endsWith('-mtp');
const baseFramework = isMtp ? framework.slice(0, -4) : framework;
const baseLabel = getFrameworkLabel(baseFramework);
// M3's `mtp` spec token renders as "EAGLE"; every other model keeps "MTP".
const mtpLabel = resolveFrameworkPartLabel(MODEL_PREFIX_MAPPING[model], 'mtp');
const frameworkLabel = isMtp ? `${baseLabel}, ${mtpLabel}` : baseLabel;
return `${gpu.toUpperCase()} (${frameworkLabel}) ${MODEL_PREFIX_MAPPING[model]} ${getPrecisionLabel(precision as Precision)}`;
const modelLabel = MODEL_PREFIX_MAPPING[model];
const hwKey = changelogConfigToHwKey(key);

if (!hwKey) {
const gpu = parts[2]?.toUpperCase() ?? '';
const framework = parts.slice(3).join('-');
const frameworkLabel = resolveFrameworkPartLabel(modelLabel, framework);
return `${gpu} (${frameworkLabel}) ${modelLabel} ${getPrecisionLabel(precision as Precision)}`;
}

// Use the same hardware entry builder and display combiner as the legend so
// aliases, compound framework names, and model-specific spec labels cannot
// drift between the two surfaces.
const hardwareLabel = getDisplayLabel(getHardwareConfig(hwKey, modelLabel));
return `${hardwareLabel} ${modelLabel} ${getPrecisionLabel(precision as Precision)}`;
}
Loading