|
| 1 | +import { useState } from 'react'; |
| 2 | +import { GlobalFilterContext } from '@/components/GlobalFilterContext'; |
| 3 | +import { InferenceContext } from '@/components/inference/InferenceContext'; |
| 4 | +import { UnofficialRunContext } from '@/components/unofficial-run-provider'; |
1 | 5 | import ScatterGraph from '@/components/inference/ui/ScatterGraph'; |
| 6 | +import ChartDisplay from '@/components/inference/ui/ChartDisplay'; |
2 | 7 | import { mountWithProviders } from '../support/test-utils'; |
3 | 8 | import { |
4 | 9 | createMockInferenceData, |
5 | 10 | createMockChartDefinition, |
6 | 11 | createMockHardwareConfig, |
| 12 | + createMockGlobalFilterContext, |
| 13 | + createMockInferenceContext, |
| 14 | + createMockUnofficialRunContext, |
7 | 15 | } from '../support/mock-data'; |
8 | | -import { Precision } from '@/lib/data-mappings'; |
| 16 | +import { Model, Precision, Sequence } from '@/lib/data-mappings'; |
| 17 | +import { buildExclusion, resolveExclusionGroups } from '@/lib/exclusion'; |
9 | 18 |
|
10 | 19 | const defaultChartDef = createMockChartDefinition(); |
11 | 20 | const hwConfig = createMockHardwareConfig(); |
@@ -331,4 +340,298 @@ describe('ScatterGraph', () => { |
331 | 340 | // No label should show the generic MTP token for M3. |
332 | 341 | cy.get('#test-scatter-m3-eagle svg .line-label text').should('not.contain.text', 'MTP'); |
333 | 342 | }); |
| 343 | + |
| 344 | + it('removes a cross-engine AgentX STP overlay before rendering', () => { |
| 345 | + const chartDefinition = createMockChartDefinition({ |
| 346 | + chartType: 'interactivity', |
| 347 | + y_tpPerGpu_roofline: 'upper_left', |
| 348 | + }); |
| 349 | + const officialData = [8, 16, 32].map((x, index) => |
| 350 | + createMockInferenceData({ |
| 351 | + hwKey: 'b200_sglang', |
| 352 | + x, |
| 353 | + y: 320 - index * 40, |
| 354 | + precision: Precision.FP4, |
| 355 | + }), |
| 356 | + ); |
| 357 | + const runUrl = 'https://github.com/x/y/actions/runs/agentx-vllm'; |
| 358 | + const overlayData = { |
| 359 | + data: [8, 16, 32].map((x, index) => |
| 360 | + createMockInferenceData({ |
| 361 | + hwKey: 'h100_vllm', |
| 362 | + x, |
| 363 | + y: 260 - index * 40, |
| 364 | + precision: Precision.FP4, |
| 365 | + run_url: runUrl, |
| 366 | + }), |
| 367 | + ), |
| 368 | + hardwareConfig: hwConfig, |
| 369 | + label: 'agentx-vllm', |
| 370 | + runUrl, |
| 371 | + }; |
| 372 | + const exclusion = buildExclusion([ |
| 373 | + { suffix: null, stripPrefixes: ['dynamo-', 'mori-', 'llmd-', 'mooncake-'] }, |
| 374 | + ]); |
| 375 | + const namespacedExclusion = { |
| 376 | + familyOf: (key: string) => |
| 377 | + exclusion.familyOf(key.startsWith('overlay:') ? key.slice('overlay:'.length) : key), |
| 378 | + groupOf: (key: string) => |
| 379 | + exclusion.groupOf(key.startsWith('overlay:') ? key.slice('overlay:'.length) : key), |
| 380 | + }; |
| 381 | + |
| 382 | + mountWithProviders( |
| 383 | + <div style={{ width: 800, height: 600 }}> |
| 384 | + <ScatterGraph |
| 385 | + chartId="test-scatter-agentx-engine-guard" |
| 386 | + modelLabel="DeepSeek V4 Pro" |
| 387 | + data={officialData} |
| 388 | + xLabel="Concurrency" |
| 389 | + yLabel="Throughput / GPU (tok/s)" |
| 390 | + chartDefinition={chartDefinition} |
| 391 | + overlayData={overlayData} |
| 392 | + /> |
| 393 | + </div>, |
| 394 | + { |
| 395 | + inference: { |
| 396 | + hardwareConfig: hwConfig, |
| 397 | + activeHwTypes: new Set(['b200_sglang']), |
| 398 | + hwTypesWithData: new Set(['b200_sglang']), |
| 399 | + selectedModel: Model.DeepSeek_V4_Pro, |
| 400 | + selectedSequence: Sequence.AgenticTraces, |
| 401 | + selectedPrecisions: [Precision.FP4], |
| 402 | + showLineLabels: true, |
| 403 | + resolveComparisonSelection: (proposed, prev = new Set()) => |
| 404 | + resolveExclusionGroups(proposed, prev, namespacedExclusion, 'keep-sticky'), |
| 405 | + }, |
| 406 | + unofficial: { |
| 407 | + activeOverlayHwTypes: new Set(['h100_vllm']), |
| 408 | + allOverlayHwTypes: new Set(['h100_vllm']), |
| 409 | + }, |
| 410 | + }, |
| 411 | + ); |
| 412 | + |
| 413 | + cy.get('#test-scatter-agentx-engine-guard svg .roofline-path').should('exist'); |
| 414 | + cy.get('#test-scatter-agentx-engine-guard svg .overlay-roofline-path').should('not.exist'); |
| 415 | + cy.get('@setActiveOverlayHwTypes').should('have.been.called'); |
| 416 | + }); |
| 417 | +}); |
| 418 | + |
| 419 | +describe('ChartDisplay engine comparison guard', () => { |
| 420 | + it('keeps cross-engine AgentX STP rows out of table mode', () => { |
| 421 | + const chartDefinition = createMockChartDefinition({ chartType: 'interactivity' }); |
| 422 | + const sglangRow = createMockInferenceData({ |
| 423 | + hwKey: 'b200_sglang', |
| 424 | + hw: 'Official SGLang', |
| 425 | + model: Model.DeepSeek_V4_Pro, |
| 426 | + precision: Precision.FP4, |
| 427 | + }); |
| 428 | + const vllmRow = createMockInferenceData({ |
| 429 | + hwKey: 'h100_vllm', |
| 430 | + hw: 'Official vLLM', |
| 431 | + model: Model.DeepSeek_V4_Pro, |
| 432 | + precision: Precision.FP4, |
| 433 | + }); |
| 434 | + const exclusion = buildExclusion([ |
| 435 | + { suffix: null, stripPrefixes: ['dynamo-', 'mori-', 'llmd-', 'mooncake-'] }, |
| 436 | + ]); |
| 437 | + const resolveSelection = (proposed: Set<string>, prev = new Set<string>()) => |
| 438 | + resolveExclusionGroups(proposed, prev, exclusion, 'keep-sticky'); |
| 439 | + |
| 440 | + mountWithProviders(<ChartDisplay />, { |
| 441 | + inference: { |
| 442 | + graphs: [ |
| 443 | + { |
| 444 | + model: Model.DeepSeek_V4_Pro, |
| 445 | + sequence: Sequence.AgenticTraces, |
| 446 | + chartDefinition, |
| 447 | + data: [sglangRow, vllmRow], |
| 448 | + }, |
| 449 | + ], |
| 450 | + selectedModel: Model.DeepSeek_V4_Pro, |
| 451 | + selectedSequence: Sequence.AgenticTraces, |
| 452 | + selectedXAxisMode: 'interactivity', |
| 453 | + activeHwTypes: new Set(['b200_sglang']), |
| 454 | + hwTypesWithData: new Set(['b200_sglang', 'h100_vllm']), |
| 455 | + resolveComparisonSelection: resolveSelection, |
| 456 | + }, |
| 457 | + globalFilters: { |
| 458 | + selectedModel: Model.DeepSeek_V4_Pro, |
| 459 | + selectedSequence: Sequence.AgenticTraces, |
| 460 | + effectiveSequence: Sequence.AgenticTraces, |
| 461 | + }, |
| 462 | + unofficial: {}, |
| 463 | + }); |
| 464 | + |
| 465 | + cy.get('[data-testid="inference-table-view-btn"]').click(); |
| 466 | + cy.get('[data-testid="inference-results-table"] tbody tr').should('have.length', 1); |
| 467 | + }); |
| 468 | + |
| 469 | + it('keeps an explicitly empty official legend out of table mode', () => { |
| 470 | + const chartDefinition = createMockChartDefinition({ chartType: 'interactivity' }); |
| 471 | + const row = createMockInferenceData({ |
| 472 | + hwKey: 'b200_sglang', |
| 473 | + model: Model.DeepSeek_V4_Pro, |
| 474 | + precision: Precision.FP4, |
| 475 | + }); |
| 476 | + |
| 477 | + mountWithProviders(<ChartDisplay />, { |
| 478 | + inference: { |
| 479 | + graphs: [ |
| 480 | + { |
| 481 | + model: Model.DeepSeek_V4_Pro, |
| 482 | + sequence: Sequence.AgenticTraces, |
| 483 | + chartDefinition, |
| 484 | + data: [row], |
| 485 | + }, |
| 486 | + ], |
| 487 | + selectedModel: Model.DeepSeek_V4_Pro, |
| 488 | + selectedSequence: Sequence.AgenticTraces, |
| 489 | + selectedXAxisMode: 'interactivity', |
| 490 | + activeHwTypes: new Set(['b200_sglang']), |
| 491 | + hwTypesWithData: new Set(['b200_sglang']), |
| 492 | + }, |
| 493 | + globalFilters: { |
| 494 | + selectedModel: Model.DeepSeek_V4_Pro, |
| 495 | + selectedSequence: Sequence.AgenticTraces, |
| 496 | + effectiveSequence: Sequence.AgenticTraces, |
| 497 | + }, |
| 498 | + unofficial: { localOfficialOverride: new Set() }, |
| 499 | + }); |
| 500 | + |
| 501 | + cy.get('[data-testid="inference-table-view-btn"]').click(); |
| 502 | + cy.contains('No data available for the current filters.').should('be.visible'); |
| 503 | + cy.get('[data-testid="inference-results-table"]').should('not.exist'); |
| 504 | + }); |
| 505 | + |
| 506 | + it('commits a new table overlay scope and preserves an explicit empty selection', () => { |
| 507 | + const chartDefinition = createMockChartDefinition({ chartType: 'interactivity' }); |
| 508 | + const exclusion = buildExclusion([ |
| 509 | + { suffix: null, stripPrefixes: ['dynamo-', 'mori-', 'llmd-', 'mooncake-'] }, |
| 510 | + ]); |
| 511 | + const namespacedExclusion = { |
| 512 | + familyOf: (key: string) => |
| 513 | + exclusion.familyOf(key.startsWith('overlay:') ? key.slice('overlay:'.length) : key), |
| 514 | + groupOf: (key: string) => |
| 515 | + exclusion.groupOf(key.startsWith('overlay:') ? key.slice('overlay:'.length) : key), |
| 516 | + }; |
| 517 | + const resolveSelection = (proposed: Set<string>, prev = new Set<string>()) => |
| 518 | + resolveExclusionGroups(proposed, prev, namespacedExclusion, 'keep-sticky'); |
| 519 | + const runInfo = { |
| 520 | + id: 123, |
| 521 | + name: 'agentx-scope-test', |
| 522 | + branch: 'agentx-scope-test', |
| 523 | + sha: 'abc123', |
| 524 | + createdAt: '2026-07-10T00:00:00Z', |
| 525 | + url: 'https://github.com/x/y/actions/runs/123', |
| 526 | + conclusion: 'success', |
| 527 | + status: 'completed', |
| 528 | + isNonMainBranch: true, |
| 529 | + }; |
| 530 | + const baseInference = createMockInferenceContext(); |
| 531 | + const baseGlobalFilters = createMockGlobalFilterContext(); |
| 532 | + const baseUnofficial = createMockUnofficialRunContext(); |
| 533 | + |
| 534 | + function OverlayScopeHarness() { |
| 535 | + const [secondScope, setSecondScope] = useState(false); |
| 536 | + const [activeOverlayKeys, setActiveOverlayKeys] = useState(new Set(['h100_sglang'])); |
| 537 | + const [, setRenderVersion] = useState(0); |
| 538 | + const model = secondScope ? Model.DeepSeek_R1 : Model.DeepSeek_V4_Pro; |
| 539 | + const officialKey = secondScope ? 'h100_vllm' : 'b200_sglang'; |
| 540 | + const overlayKeys = secondScope |
| 541 | + ? ['b200_vllm', 'h200_sglang'] |
| 542 | + : ['h100_sglang', 'h200_sglang']; |
| 543 | + const officialRows = [ |
| 544 | + createMockInferenceData({ |
| 545 | + hwKey: officialKey, |
| 546 | + model, |
| 547 | + precision: Precision.FP4, |
| 548 | + }), |
| 549 | + ]; |
| 550 | + const overlayRows = overlayKeys.map((hwKey, index) => |
| 551 | + createMockInferenceData({ |
| 552 | + hwKey, |
| 553 | + model, |
| 554 | + precision: Precision.FP4, |
| 555 | + x: 8 + index * 8, |
| 556 | + run_url: runInfo.url, |
| 557 | + }), |
| 558 | + ); |
| 559 | + const inference = { |
| 560 | + ...baseInference, |
| 561 | + graphs: [ |
| 562 | + { |
| 563 | + model, |
| 564 | + sequence: Sequence.AgenticTraces, |
| 565 | + chartDefinition, |
| 566 | + data: officialRows, |
| 567 | + }, |
| 568 | + ], |
| 569 | + selectedModel: model, |
| 570 | + selectedSequence: Sequence.AgenticTraces, |
| 571 | + selectedXAxisMode: 'interactivity' as const, |
| 572 | + selectedXAxisMetric: 'p90_ttft', |
| 573 | + activeHwTypes: new Set([officialKey]), |
| 574 | + hwTypesWithData: new Set([officialKey]), |
| 575 | + resolveComparisonSelection: resolveSelection, |
| 576 | + }; |
| 577 | + const globalFilters = { |
| 578 | + ...baseGlobalFilters, |
| 579 | + selectedModel: model, |
| 580 | + selectedSequence: Sequence.AgenticTraces, |
| 581 | + effectiveSequence: Sequence.AgenticTraces, |
| 582 | + }; |
| 583 | + const unofficial = { |
| 584 | + ...baseUnofficial, |
| 585 | + isUnofficialRun: true, |
| 586 | + unofficialRunInfo: runInfo, |
| 587 | + unofficialRunInfos: [runInfo], |
| 588 | + runIndexByUrl: { [runInfo.url]: 0, [String(runInfo.id)]: 0 }, |
| 589 | + getOverlayData: () => ({ data: overlayRows, hardwareConfig: hwConfig }), |
| 590 | + activeOverlayHwTypes: activeOverlayKeys, |
| 591 | + setActiveOverlayHwTypes: setActiveOverlayKeys, |
| 592 | + allOverlayHwTypes: new Set(['h100_sglang', 'h200_sglang', 'b200_vllm']), |
| 593 | + }; |
| 594 | + |
| 595 | + return ( |
| 596 | + <GlobalFilterContext.Provider value={globalFilters}> |
| 597 | + <UnofficialRunContext.Provider value={unofficial}> |
| 598 | + <InferenceContext.Provider value={inference}> |
| 599 | + <button data-testid="change-overlay-scope" onClick={() => setSecondScope(true)}> |
| 600 | + Change scope |
| 601 | + </button> |
| 602 | + <button |
| 603 | + data-testid="clear-overlay-scope" |
| 604 | + onClick={() => setActiveOverlayKeys(new Set())} |
| 605 | + > |
| 606 | + Clear overlays |
| 607 | + </button> |
| 608 | + <button |
| 609 | + data-testid="rerender-overlay-scope" |
| 610 | + onClick={() => setRenderVersion((version) => version + 1)} |
| 611 | + > |
| 612 | + Rerender |
| 613 | + </button> |
| 614 | + <ChartDisplay /> |
| 615 | + </InferenceContext.Provider> |
| 616 | + </UnofficialRunContext.Provider> |
| 617 | + </GlobalFilterContext.Provider> |
| 618 | + ); |
| 619 | + } |
| 620 | + |
| 621 | + mountWithProviders(<OverlayScopeHarness />); |
| 622 | + cy.get('[data-testid="inference-table-view-btn"]').click(); |
| 623 | + cy.get('[data-testid="inference-results-table"] tbody tr').should('have.length', 2); |
| 624 | + |
| 625 | + cy.get('[data-testid="change-overlay-scope"]').click(); |
| 626 | + cy.get('[data-testid="inference-results-table"] tbody tr').should('have.length', 2); |
| 627 | + cy.get('[data-testid="rerender-overlay-scope"]').click(); |
| 628 | + cy.get('[data-testid="inference-results-table"] tbody tr').should('have.length', 2); |
| 629 | + |
| 630 | + cy.get('[data-testid="clear-overlay-scope"]').click(); |
| 631 | + cy.get('[data-testid="inference-results-table"] tbody tr').should('have.length', 1); |
| 632 | + cy.get('[data-testid="rerender-overlay-scope"]').click(); |
| 633 | + cy.get('[data-testid="inference-results-table"] tbody tr').should('have.length', 1); |
| 634 | + cy.get('[data-testid="inference-chart-view-btn"]').click(); |
| 635 | + cy.get('#chart-0 svg .unofficial-overlay-pt').should('not.exist'); |
| 636 | + }); |
334 | 637 | }); |
0 commit comments