Skip to content

Commit 1e60c7b

Browse files
authored
fix(agentic): show runtime metadata in point details (#609)
Expose KV offload, transfer, and router metadata through the point-detail API; render it in English and Simplified Chinese; and version the composite cache response. 中文:在 Agentic 数据点详情 API 中补充 KV 卸载、传输引擎和路由器元数据,并在英文与简体中文界面中展示;同时为组合响应增加版本化缓存命名空间。
1 parent 115da5f commit 1e60c7b

12 files changed

Lines changed: 277 additions & 51 deletions

File tree

packages/app/cypress/e2e/agentic-point-time-series.cy.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,15 +215,19 @@ const pointMeta = {
215215
spec_method: 'none',
216216
disagg: true,
217217
conc: 128,
218-
offload_mode: 'off',
218+
offload_mode: 'on',
219+
kv_offloading: 'dram',
220+
kv_offload_backend: 'lmcache',
221+
kv_offload_backend_version: '0.5.1',
222+
kv_p2p_transfer: 'mooncake',
223+
router_name: 'vllm-router',
224+
router_version: '0.1.14',
219225
isl: null,
220226
osl: null,
221227
benchmark_type: 'agentic_traces',
222228
date: '2026-06-23',
223229
run_url: null,
224230
server_gpu_cache_hit_rate: 0.5,
225-
// Reproduces historical rows that retained a CPU hit metric after offload
226-
// was disabled. The agentic point summary must suppress this stale value.
227231
server_cpu_cache_hit_rate: 0.42,
228232
};
229233

@@ -299,8 +303,17 @@ describe('Agentic point orchestrator metric sources', () => {
299303
});
300304

301305
it('switches every server chart to an orchestrator-normalized worker', () => {
302-
cy.contains('GPU cache hit').should('be.visible');
303-
cy.contains('CPU cache hit').should('not.exist');
306+
cy.get('[data-testid="point-summary"]')
307+
.should('contain.text', 'Offload Type')
308+
.and('contain.text', 'DRAM')
309+
.and('contain.text', 'KV Offload Engine')
310+
.and('contain.text', 'LMCache 0.5.1')
311+
.and('contain.text', 'KV Transfer Engine')
312+
.and('contain.text', 'Mooncake')
313+
.and('contain.text', 'Router')
314+
.and('contain.text', 'vLLM Router 0.1.14')
315+
.and('contain.text', 'GPU cache hit')
316+
.and('contain.text', 'CPU cache hit');
304317

305318
cy.get('[data-testid="metric-source-toolbar"]')
306319
.should('have.css', 'position', 'sticky')

packages/app/src/app/api/v1/agentic-cache-keys.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ vi.mock('@/lib/api-cache', () => ({
2525
}));
2626

2727
import { STATS_VERSION } from '@semianalysisai/inferencex-db/queries/agentic-aggregates';
28-
import { CHART_SERIES_VERSION } from '@semianalysisai/inferencex-db/etl/compute-chart-series';
2928
import { REQUEST_TIMELINE_VERSION } from '@semianalysisai/inferencex-db/etl/compute-request-timeline';
29+
import { TRACE_SERVER_METRICS_VERSION } from '@semianalysisai/inferencex-db/queries/trace-server-metrics';
3030

3131
import { CACHE_KEY_PREFIX as derivedAgenticMetricsKey } from './derived-agentic-metrics/route';
3232
import { CACHE_KEY_PREFIX as agenticAggregatesKey } from './agentic-aggregates/route';
@@ -47,8 +47,8 @@ describe('agentic blob-cache keys are version-derived', () => {
4747
expect(requestTimelineKey).toBe(`request-timeline-v${REQUEST_TIMELINE_VERSION}`);
4848
});
4949

50-
it('trace-server-metrics key embeds CHART_SERIES_VERSION', () => {
51-
expect(traceServerMetricsKey).toBe(`trace-server-metrics-v${CHART_SERIES_VERSION}`);
50+
it('trace-server-metrics key embeds its composite response version', () => {
51+
expect(traceServerMetricsKey).toBe(`trace-server-metrics-v${TRACE_SERVER_METRICS_VERSION}`);
5252
});
5353

5454
it('trace-histograms key embeds REQUEST_TIMELINE_VERSION (its payload is read from request_timeline)', () => {

packages/app/src/app/api/v1/trace-server-metrics/route.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { CHART_SERIES_VERSION } from '@semianalysisai/inferencex-db/etl/compute-chart-series';
21
import { getDb } from '@semianalysisai/inferencex-db/connection';
32

43
import {
54
getTraceServerMetrics,
5+
TRACE_SERVER_METRICS_VERSION,
66
type TraceServerMetrics,
77
} from '@semianalysisai/inferencex-db/queries/trace-server-metrics';
88

@@ -12,12 +12,13 @@ import { idQueryRoute } from '../id-routes';
1212

1313
export const dynamic = 'force-dynamic';
1414

15-
// Key derived from CHART_SERIES_VERSION (governs the `chart_series` payload).
15+
// Key derived from TRACE_SERVER_METRICS_VERSION (governs chart_series plus
16+
// the separately queried point-metadata payload).
1617
// The blob cache is write-once with no post-backfill purge, so the
1718
// version-derived key is what rolls the namespace on a bump — a hand-written
1819
// string would serve stale blob-cached series forever.
1920
/** Version-derived blob-cache key namespace (exported for the key-derivation test). */
20-
export const CACHE_KEY_PREFIX = `trace-server-metrics-v${CHART_SERIES_VERSION}`;
21+
export const CACHE_KEY_PREFIX = `trace-server-metrics-v${TRACE_SERVER_METRICS_VERSION}`;
2122

2223
const getCachedTraceServerMetrics = cachedQuery(
2324
(id: number): Promise<TraceServerMetrics | null> => getTraceServerMetrics(getDb(), id),

packages/app/src/components/inference/agentic-point/point-summary.test.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { createElement } from 'react';
22
import { renderToStaticMarkup } from 'react-dom/server';
3-
import { describe, expect, it } from 'vitest';
3+
import { describe, expect, it, vi } from 'vitest';
4+
5+
const localeState = vi.hoisted(() => ({ pathname: '/inference/agentic/206885' }));
6+
vi.mock('next/navigation', () => ({
7+
usePathname: () => localeState.pathname,
8+
}));
49

510
import type { PointMeta } from '@/hooks/api/use-trace-server-metrics';
611

@@ -17,6 +22,12 @@ function meta(overrides: Partial<PointMeta> = {}): PointMeta {
1722
disagg: true,
1823
conc: 128,
1924
offload_mode: 'off',
25+
kv_offloading: null,
26+
kv_offload_backend: null,
27+
kv_offload_backend_version: null,
28+
kv_p2p_transfer: null,
29+
router_name: null,
30+
router_version: null,
2031
isl: null,
2132
osl: null,
2233
benchmark_type: 'agentic_traces',
@@ -44,4 +55,50 @@ describe('PointSummary', () => {
4455
expect(html).toContain('CPU cache hit');
4556
expect(html).toContain('42.00%');
4657
});
58+
59+
it('shows runtime component names and independently reported versions', () => {
60+
const html = renderToStaticMarkup(
61+
createElement(PointSummary, {
62+
meta: meta({
63+
offload_mode: 'on',
64+
kv_offloading: 'dram',
65+
kv_offload_backend: 'lmcache',
66+
kv_offload_backend_version: '0.5.1',
67+
kv_p2p_transfer: 'mooncake',
68+
router_name: 'vllm-router',
69+
router_version: '0.1.14',
70+
}),
71+
}),
72+
);
73+
74+
expect(html).toContain('Offload Type');
75+
expect(html).toContain('DRAM');
76+
expect(html).toContain('KV Offload Engine');
77+
expect(html).toContain('LMCache 0.5.1');
78+
expect(html).toContain('KV Transfer Engine');
79+
expect(html).toContain('Mooncake');
80+
expect(html).toContain('Router');
81+
expect(html).toContain('vLLM Router 0.1.14');
82+
});
83+
84+
it('renders runtime metadata labels in Simplified Chinese on /zh', () => {
85+
localeState.pathname = '/zh/inference/agentic/206885';
86+
const html = renderToStaticMarkup(
87+
createElement(PointSummary, {
88+
meta: meta({
89+
kv_offloading: 'dram',
90+
kv_offload_backend: 'hicache',
91+
router_name: 'sglang-router',
92+
router_version: '0.3.2',
93+
}),
94+
}),
95+
);
96+
localeState.pathname = '/inference/agentic/206885';
97+
98+
expect(html).toContain('卸载类型');
99+
expect(html).toContain('KV 卸载引擎');
100+
expect(html).toContain('HiCache');
101+
expect(html).toContain('路由器');
102+
expect(html).toContain('SGLang Router 0.3.2');
103+
});
47104
});

packages/app/src/components/inference/agentic-point/point-summary.tsx

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,46 @@
33
import type { ReactNode } from 'react';
44

55
import type { PointMeta } from '@/hooks/api/use-trace-server-metrics';
6+
import type { Locale } from '@/lib/i18n';
67
import { isKvOffloadEnabled } from '@/lib/kv-offload';
8+
import { useLocale } from '@/lib/use-locale';
9+
import {
10+
offloadTypeLabel,
11+
versionedComponentLabel,
12+
} from '@/components/inference/utils/runtime-metadata-labels';
13+
14+
const STRINGS = {
15+
en: {
16+
selectedPoint: 'Selected point',
17+
disagg: 'disagg',
18+
githubRun: 'GitHub Actions run →',
19+
offloadType: 'Offload Type',
20+
offloadBackend: 'KV Offload Engine',
21+
transferEngine: 'KV Transfer Engine',
22+
router: 'Router',
23+
concurrency: 'Concurrency',
24+
gpuCacheHit: 'GPU cache hit',
25+
cpuCacheHit: 'CPU cache hit',
26+
enabledLegacy: 'Enabled (legacy data)',
27+
disabledLegacy: 'Disabled (legacy data)',
28+
none: 'None',
29+
},
30+
zh: {
31+
selectedPoint: '已选数据点',
32+
disagg: '解耦',
33+
githubRun: 'GitHub Actions 运行 →',
34+
offloadType: '卸载类型',
35+
offloadBackend: 'KV 卸载引擎',
36+
transferEngine: 'KV 传输引擎',
37+
router: '路由器',
38+
concurrency: '并发数',
39+
gpuCacheHit: 'GPU Cache 命中率',
40+
cpuCacheHit: 'CPU Cache 命中率',
41+
enabledLegacy: '已启用(旧版数据)',
42+
disabledLegacy: '已禁用(旧版数据)',
43+
none: '无',
44+
},
45+
} as const;
746

847
const fmtPct = (v: number | null | undefined): string =>
948
v === null || v === undefined || Number.isNaN(v) ? '—' : `${(v * 100).toFixed(2)}%`;
@@ -17,16 +56,32 @@ function MetaLine({ label, value }: { label: string; value: ReactNode }) {
1756
);
1857
}
1958

20-
/** Selected-point header: config facts (offload, concurrency, cache hit rates, ISL/OSL). */
59+
function offloadDisplay(meta: PointMeta, locale: Locale): string {
60+
const t = STRINGS[locale];
61+
const type = meta.kv_offloading?.trim();
62+
if (type) return type.toLowerCase() === 'none' ? t.none : offloadTypeLabel(type);
63+
if (!meta.offload_mode) return t.none;
64+
return meta.offload_mode.toLowerCase() === 'on' ? t.enabledLegacy : t.disabledLegacy;
65+
}
66+
67+
/** Selected-point header: runtime components, concurrency, cache hit rates, and ISL/OSL. */
2168
export function PointSummary({ meta }: { meta: PointMeta }) {
69+
const locale = useLocale();
70+
const t = STRINGS[locale];
2271
const showCpuCacheHit = isKvOffloadEnabled(meta);
72+
const offloadBackend = versionedComponentLabel(
73+
meta.kv_offload_backend,
74+
meta.kv_offload_backend_version,
75+
);
76+
const transferEngine = versionedComponentLabel(meta.kv_p2p_transfer, null);
77+
const router = versionedComponentLabel(meta.router_name, meta.router_version);
2378

2479
return (
25-
<div className="mb-4">
80+
<div className="mb-4" data-testid="point-summary">
2681
<div className="flex items-baseline justify-between gap-3 mb-2">
2782
<p className="text-sm text-muted-foreground">
28-
Selected point
29-
{meta.disagg ? ' · disagg' : ''}
83+
{t.selectedPoint}
84+
{meta.disagg ? ` · ${t.disagg}` : ''}
3085
{meta.spec_method && meta.spec_method !== 'none' ? ` · spec=${meta.spec_method}` : ''}
3186
</p>
3287
{meta.run_url && (
@@ -36,16 +91,19 @@ export function PointSummary({ meta }: { meta: PointMeta }) {
3691
rel="noopener noreferrer"
3792
className="text-xs text-muted-foreground hover:text-foreground underline"
3893
>
39-
GitHub Actions run →
94+
{t.githubRun}
4095
</a>
4196
)}
4297
</div>
4398
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3">
44-
<MetaLine label="Offload" value={(meta.offload_mode ?? 'off').toUpperCase()} />
45-
<MetaLine label="Concurrency" value={meta.conc} />
46-
<MetaLine label="GPU cache hit" value={fmtPct(meta.server_gpu_cache_hit_rate)} />
99+
<MetaLine label={t.offloadType} value={offloadDisplay(meta, locale)} />
100+
{offloadBackend && <MetaLine label={t.offloadBackend} value={offloadBackend} />}
101+
{transferEngine && <MetaLine label={t.transferEngine} value={transferEngine} />}
102+
{router && <MetaLine label={t.router} value={router} />}
103+
<MetaLine label={t.concurrency} value={meta.conc} />
104+
<MetaLine label={t.gpuCacheHit} value={fmtPct(meta.server_gpu_cache_hit_rate)} />
47105
{showCpuCacheHit && (
48-
<MetaLine label="CPU cache hit" value={fmtPct(meta.server_cpu_cache_hit_rate)} />
106+
<MetaLine label={t.cpuCacheHit} value={fmtPct(meta.server_cpu_cache_hit_rate)} />
49107
)}
50108
{meta.isl !== null && <MetaLine label="ISL" value={meta.isl} />}
51109
{meta.osl !== null && <MetaLine label="OSL" value={meta.osl} />}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { describe, expect, it } from 'vitest';
2+
3+
import {
4+
cacheImplementationLabel,
5+
offloadTypeLabel,
6+
versionedComponentLabel,
7+
} from './runtime-metadata-labels';
8+
9+
describe('runtime metadata labels', () => {
10+
it('normalizes known component names and preserves unknown names', () => {
11+
expect(cacheImplementationLabel('vllm-simple')).toBe('vLLM Simple');
12+
expect(cacheImplementationLabel('MOONCAKE')).toBe('Mooncake');
13+
expect(cacheImplementationLabel('custom-engine')).toBe('custom-engine');
14+
});
15+
16+
it('combines independently reported component versions', () => {
17+
expect(versionedComponentLabel('lmcache', '0.5.1')).toBe('LMCache 0.5.1');
18+
expect(versionedComponentLabel('hicache', null)).toBe('HiCache');
19+
expect(versionedComponentLabel(null, 'ignored')).toBeNull();
20+
});
21+
22+
it('formats DRAM and other offload types consistently', () => {
23+
expect(offloadTypeLabel('dram')).toBe('DRAM');
24+
expect(offloadTypeLabel('cpu')).toBe('CPU');
25+
});
26+
});
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const CACHE_IMPLEMENTATION_LABELS: Record<string, string> = {
2+
hicache: 'HiCache',
3+
lmcache: 'LMCache',
4+
mooncake: 'Mooncake',
5+
mori: 'MoRI',
6+
moriio: 'MoRI-IO',
7+
'mori-io': 'MoRI-IO',
8+
nixl: 'NIXL',
9+
atomesh: 'AtoMesh',
10+
'vllm-native': 'vLLM Native',
11+
'vllm-router': 'vLLM Router',
12+
'vllm-simple': 'vLLM Simple',
13+
'sglang-router': 'SGLang Router',
14+
};
15+
16+
export const cacheImplementationLabel = (value: string): string =>
17+
CACHE_IMPLEMENTATION_LABELS[value.toLowerCase()] ?? value;
18+
19+
export const offloadTypeLabel = (value: string): string => {
20+
if (value.toLowerCase() === 'dram') return 'DRAM';
21+
return value.toUpperCase();
22+
};
23+
24+
export const versionedComponentLabel = (
25+
name: string | null | undefined,
26+
version: string | null | undefined,
27+
): string | null => {
28+
if (!name) return null;
29+
const label = cacheImplementationLabel(name);
30+
return version ? `${label} ${version}` : label;
31+
};

0 commit comments

Comments
 (0)