Skip to content

Commit 9ec8cc1

Browse files
authored
fix(inference): use agentic label defaults / 修正 agentic 标签默认值 (#545)
* fix(inference): use agentic label defaults Apply scenario-aware defaults so agentic charts show parallelism labels and hide line labels, while fixed-sequence behavior remains unchanged. Preserve explicit and legacy URL overrides with scenario-aware serialization. 中文:修正推理图表的 agentic 标签默认值 按场景应用默认配置:agentic 图表默认显示并行配置标签并隐藏曲线标签,同时保持固定序列场景的现有行为不变。通过按场景序列化参数,继续兼容显式及旧版 URL 覆盖。 * test(inference): cover scenario label defaults Add focused regression coverage for agentic and fixed-sequence label defaults, explicit URL overrides, and fixed-sequence URL serialization. 中文:补充推理场景标签默认值测试 新增定向回归测试,覆盖 agentic 与固定序列场景的标签默认值、显式 URL 覆盖及固定序列 URL 序列化。
1 parent f3548e1 commit 9ec8cc1

4 files changed

Lines changed: 221 additions & 23 deletions

File tree

packages/app/cypress/e2e/ttft-x-axis-toggle.cy.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,24 @@ const agenticBenchmarks = agenticGpus.flatMap((g) =>
123123
})),
124124
);
125125

126+
const fixedSequenceBenchmarks = agenticBenchmarks.map((row, index) => ({
127+
...row,
128+
id: 910000 + index,
129+
isl: 8192,
130+
osl: 1024,
131+
benchmark_type: 'single_turn',
132+
}));
133+
126134
const interceptAgenticData = () => {
127135
cy.intercept('GET', '/api/v1/availability', { body: agenticAvailability }).as('availability');
128136
cy.intercept('GET', '/api/v1/benchmarks*', { body: agenticBenchmarks }).as('benchmarks');
129137
};
130138

139+
const interceptFixedSequenceData = () => {
140+
cy.intercept('GET', '/api/v1/availability', { body: agenticAvailability }).as('availability');
141+
cy.intercept('GET', '/api/v1/benchmarks*', { body: fixedSequenceBenchmarks }).as('benchmarks');
142+
};
143+
131144
describe('X-Axis Mode Toggle (inference chart)', () => {
132145
before(() => {
133146
interceptAgenticData();
@@ -152,6 +165,26 @@ describe('X-Axis Mode Toggle (inference chart)', () => {
152165
cy.get('[data-testid="chart-figure"] h2').should('contain.text', 'Interactivity');
153166
});
154167

168+
it('defaults to parallelism labels without line labels for the agentic view', () => {
169+
cy.get('#scatter-parallelism-labels').should('have.attr', 'data-state', 'checked');
170+
cy.get('#scatter-point-labels').should('have.attr', 'data-state', 'checked');
171+
cy.get('#scatter-line-labels').should('have.attr', 'data-state', 'unchecked');
172+
});
173+
174+
it('honors explicit label URL overrides for the agentic view', () => {
175+
interceptAgenticData();
176+
cy.visit('/inference?i_label=0&i_advlabel=0&i_linelabel=1', {
177+
onBeforeLoad(win) {
178+
win.localStorage.setItem('inferencex-star-modal-dismissed', String(Date.now()));
179+
unlockAgenticGate(win);
180+
},
181+
});
182+
cy.get('[data-testid="scenario-selector"]').should('contain.text', 'Agentic Traces');
183+
cy.get('#scatter-parallelism-labels').should('have.attr', 'data-state', 'unchecked');
184+
cy.get('#scatter-point-labels').should('have.attr', 'data-state', 'unchecked');
185+
cy.get('#scatter-line-labels').should('have.attr', 'data-state', 'checked');
186+
});
187+
155188
it('switches the x-axis to TTFT and updates the heading', () => {
156189
cy.get('[data-testid="x-axis-mode-ttft"]').click();
157190
cy.get('[data-testid="x-axis-mode-ttft"]').should('have.attr', 'aria-selected', 'true');
@@ -201,6 +234,34 @@ describe('X-Axis Mode Toggle (inference chart)', () => {
201234
});
202235
});
203236

237+
describe('Label defaults for fixed-sequence scenarios', () => {
238+
it('keeps parallelism labels off and line labels on by default', () => {
239+
interceptFixedSequenceData();
240+
cy.visit('/inference?i_seq=8k%2F1k', {
241+
onBeforeLoad(win) {
242+
win.localStorage.setItem('inferencex-star-modal-dismissed', String(Date.now()));
243+
},
244+
});
245+
cy.get('[data-testid="scenario-selector"]').should('contain.text', '8K / 1K');
246+
cy.get('#scatter-parallelism-labels').should('have.attr', 'data-state', 'unchecked');
247+
cy.get('#scatter-point-labels').should('have.attr', 'data-state', 'unchecked');
248+
cy.get('#scatter-line-labels').should('have.attr', 'data-state', 'checked');
249+
});
250+
251+
it('honors explicit label URL overrides', () => {
252+
interceptFixedSequenceData();
253+
cy.visit('/inference?i_seq=8k%2F1k&i_label=1&i_advlabel=1&i_linelabel=0', {
254+
onBeforeLoad(win) {
255+
win.localStorage.setItem('inferencex-star-modal-dismissed', String(Date.now()));
256+
},
257+
});
258+
cy.get('[data-testid="scenario-selector"]').should('contain.text', '8K / 1K');
259+
cy.get('#scatter-parallelism-labels').should('have.attr', 'data-state', 'checked');
260+
cy.get('#scatter-point-labels').should('have.attr', 'data-state', 'checked');
261+
cy.get('#scatter-line-labels').should('have.attr', 'data-state', 'unchecked');
262+
});
263+
});
264+
204265
// ---------------------------------------------------------------------------
205266
// Overlay path — regression coverage for unofficial-run overlays with agentic
206267
// x-axis modes (finding #8 / AGENTS.md: chart features must have overlay tests).

packages/app/src/components/inference/InferenceContext.tsx

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import {
6464
type XAxisMode,
6565
} from './hooks/useChartData';
6666
import { resolveComparisonEntries } from './utils/comparisonEntry';
67+
import { resolveLabelState, serializeLabelState } from './utils/label-defaults';
6768
import {
6869
EMPTY_QUICK_FILTERS,
6970
type DisaggMode,
@@ -244,30 +245,24 @@ export function InferenceProvider({
244245
});
245246

246247
const [hideNonOptimal, setHideNonOptimal] = useState(() => getUrlParam('i_optimal') !== '0');
247-
const [showPointLabels, setShowPointLabels] = useState(() => {
248-
// Legacy `?i_nolabel=1` from before the rename: keep hiding point labels.
249-
if (getUrlParam('i_nolabel') === '1') return false;
250-
if (getUrlParam('i_label') === '0') return false;
251-
if (getUrlParam('i_label') === '1') return true;
252-
// Advanced (parallelism) labels are a richer form of point label; a share
253-
// link that requests them must auto-enable point labels so they actually
254-
// render (mirrors the runtime toggle coupling in ScatterGraph). A later
255-
// explicit i_nolabel=1 still wins — it is checked first above.
256-
if (getUrlParam('i_advlabel') === '1') return true;
257-
// Default off: per-point labels (TP + concurrency) clutter the chart; the
258-
// per-line hardware labels (on by default) are the primary annotation.
259-
return false;
260-
});
261-
const [logScale, setLogScale] = useState(() => getUrlParam('i_log') === '1');
262-
// Parallelism labels default off (?i_advlabel=1 overrides on).
263-
const [useAdvancedLabels, setUseAdvancedLabels] = useState(
264-
() => getUrlParam('i_advlabel') === '1',
248+
const labelScenarioKind = sequenceKind(effectiveSequence);
249+
const initialLabelState = useMemo(
250+
() =>
251+
resolveLabelState('fixed-seq', {
252+
i_label: getUrlParam('i_label'),
253+
i_nolabel: getUrlParam('i_nolabel'),
254+
i_advlabel: getUrlParam('i_advlabel'),
255+
i_linelabel: getUrlParam('i_linelabel'),
256+
}),
257+
[getUrlParam],
265258
);
259+
const [showPointLabels, setShowPointLabels] = useState(initialLabelState.showPointLabels);
260+
const [logScale, setLogScale] = useState(() => getUrlParam('i_log') === '1');
261+
const [useAdvancedLabels, setUseAdvancedLabels] = useState(initialLabelState.useAdvancedLabels);
266262
const [showGradientLabels, setShowGradientLabels] = useState(
267263
() => getUrlParam('i_gradlabel') === '1',
268264
);
269-
// Line labels default on (?i_linelabel=0 overrides off).
270-
const [showLineLabels, setShowLineLabels] = useState(() => getUrlParam('i_linelabel') !== '0');
265+
const [showLineLabels, setShowLineLabels] = useState(initialLabelState.showLineLabels);
271266
const [showSpeedOverlay, setShowSpeedOverlay] = useState(() => getUrlParam('i_speed') === '1');
272267
const [showMinecraftOverlay, setShowMinecraftOverlay] = useState(
273268
() => getUrlParam('i_mc') === '1',
@@ -540,6 +535,19 @@ export function InferenceProvider({
540535
setTrackedConfigs((prev) => (prev.length > 0 ? [] : prev));
541536
}, [selectedModel, effectiveSequence, effectivePrecisions, selectedYAxisMetric]);
542537

538+
useEffect(() => {
539+
if (!sequenceResolved) return;
540+
const labelState = resolveLabelState(labelScenarioKind, {
541+
i_label: getUrlParam('i_label'),
542+
i_nolabel: getUrlParam('i_nolabel'),
543+
i_advlabel: getUrlParam('i_advlabel'),
544+
i_linelabel: getUrlParam('i_linelabel'),
545+
});
546+
setShowPointLabels(labelState.showPointLabels);
547+
setUseAdvancedLabels(labelState.useAdvancedLabels);
548+
setShowLineLabels(labelState.showLineLabels);
549+
}, [labelScenarioKind, sequenceResolved, getUrlParam]);
550+
543551
// Reconcile the x-axis mode with the scenario kind:
544552
// - On mount with no `i_xmode` URL param: snap to the kind's natural default
545553
// (interactivity for both agentic and fixed-sequence scenarios). The state was initialized
@@ -1034,6 +1042,12 @@ export function InferenceProvider({
10341042
return [...activeHwTypes].toSorted().join(',');
10351043
}, [activeHwTypes, hwTypesWithData]);
10361044

1045+
const serializedLabelState = serializeLabelState(labelScenarioKind, {
1046+
showPointLabels,
1047+
useAdvancedLabels,
1048+
showLineLabels,
1049+
});
1050+
10371051
useUrlStateSync(
10381052
{
10391053
i_metric: selectedYAxisMetric,
@@ -1043,17 +1057,17 @@ export function InferenceProvider({
10431057
i_dstart: selectedDateRange.startDate,
10441058
i_dend: selectedDateRange.endDate,
10451059
i_optimal: hideNonOptimal ? '' : '0',
1046-
i_label: showPointLabels ? '1' : '',
1060+
i_label: serializedLabelState.i_label,
10471061
i_hc: highContrast ? '1' : '',
10481062
i_log: logScale ? '1' : '',
10491063
i_xmetric: selectedXAxisMetric || '',
10501064
i_e2e_xmetric: selectedE2eXAxisMetric || '',
10511065
i_xmode: selectedXAxisMode,
10521066
i_scale: scaleType,
10531067
i_legend: isLegendExpanded ? '' : '0',
1054-
i_advlabel: useAdvancedLabels ? '1' : '',
1068+
i_advlabel: serializedLabelState.i_advlabel,
10551069
i_gradlabel: showGradientLabels ? '1' : '',
1056-
i_linelabel: showLineLabels ? '' : '0',
1070+
i_linelabel: serializedLabelState.i_linelabel,
10571071
i_speed: showSpeedOverlay ? '1' : '',
10581072
i_mc: showMinecraftOverlay ? '1' : '',
10591073
i_active: iActiveStr,
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { describe, expect, it } from 'vitest';
2+
3+
import { resolveLabelState, serializeLabelState } from './label-defaults';
4+
5+
describe('resolveLabelState', () => {
6+
it('uses uncluttered fixed-sequence defaults', () => {
7+
expect(resolveLabelState('fixed-seq', {})).toEqual({
8+
showPointLabels: false,
9+
useAdvancedLabels: false,
10+
showLineLabels: true,
11+
});
12+
});
13+
14+
it('uses parallelism labels instead of line labels for agentic scenarios', () => {
15+
expect(resolveLabelState('agentic', {})).toEqual({
16+
showPointLabels: true,
17+
useAdvancedLabels: true,
18+
showLineLabels: false,
19+
});
20+
});
21+
22+
it('preserves explicit and legacy URL overrides', () => {
23+
expect(
24+
resolveLabelState('agentic', {
25+
i_nolabel: '1',
26+
i_advlabel: '0',
27+
i_linelabel: '1',
28+
}),
29+
).toEqual({
30+
showPointLabels: false,
31+
useAdvancedLabels: false,
32+
showLineLabels: true,
33+
});
34+
});
35+
});
36+
37+
describe('serializeLabelState', () => {
38+
it('omits the scenario defaults', () => {
39+
expect(serializeLabelState('agentic', resolveLabelState('agentic', {}))).toEqual({
40+
i_label: '',
41+
i_advlabel: '',
42+
i_linelabel: '',
43+
});
44+
});
45+
46+
it('serializes deviations from agentic defaults', () => {
47+
expect(
48+
serializeLabelState('agentic', {
49+
showPointLabels: false,
50+
useAdvancedLabels: false,
51+
showLineLabels: true,
52+
}),
53+
).toEqual({
54+
i_label: '0',
55+
i_advlabel: '0',
56+
i_linelabel: '1',
57+
});
58+
});
59+
60+
it('preserves fixed-sequence defaults and serializes their deviations', () => {
61+
expect(serializeLabelState('fixed-seq', resolveLabelState('fixed-seq', {}))).toEqual({
62+
i_label: '',
63+
i_advlabel: '',
64+
i_linelabel: '',
65+
});
66+
expect(
67+
serializeLabelState('fixed-seq', {
68+
showPointLabels: true,
69+
useAdvancedLabels: true,
70+
showLineLabels: false,
71+
}),
72+
).toEqual({
73+
i_label: '1',
74+
i_advlabel: '1',
75+
i_linelabel: '0',
76+
});
77+
});
78+
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import type { ScenarioKind } from '@/lib/data-mappings';
2+
3+
export interface LabelState {
4+
showPointLabels: boolean;
5+
useAdvancedLabels: boolean;
6+
showLineLabels: boolean;
7+
}
8+
9+
type LabelUrlParams = Partial<
10+
Record<'i_label' | 'i_nolabel' | 'i_advlabel' | 'i_linelabel', string>
11+
>;
12+
13+
export function resolveLabelState(kind: ScenarioKind, params: LabelUrlParams): LabelState {
14+
const agentic = kind === 'agentic';
15+
16+
let showPointLabels = agentic;
17+
if (params.i_nolabel === '1' || params.i_label === '0') showPointLabels = false;
18+
else if (params.i_label === '1') showPointLabels = true;
19+
else if (params.i_advlabel === '1') showPointLabels = true;
20+
21+
return {
22+
showPointLabels,
23+
useAdvancedLabels:
24+
params.i_advlabel === '1' ? true : params.i_advlabel === '0' ? false : agentic,
25+
showLineLabels:
26+
params.i_linelabel === '1' ? true : params.i_linelabel === '0' ? false : !agentic,
27+
};
28+
}
29+
30+
export function serializeLabelState(kind: ScenarioKind, state: LabelState): LabelUrlParams {
31+
const defaults = resolveLabelState(kind, {});
32+
33+
return {
34+
i_label:
35+
state.showPointLabels === defaults.showPointLabels ? '' : state.showPointLabels ? '1' : '0',
36+
i_advlabel:
37+
state.useAdvancedLabels === defaults.useAdvancedLabels
38+
? ''
39+
: state.useAdvancedLabels
40+
? '1'
41+
: '0',
42+
i_linelabel:
43+
state.showLineLabels === defaults.showLineLabels ? '' : state.showLineLabels ? '1' : '0',
44+
};
45+
}

0 commit comments

Comments
 (0)