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
42 changes: 38 additions & 4 deletions apps/web/src/features/monitoring/MonitoringCenterPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
type MonitoringAccountAuthState,
} from '@/features/monitoring/accountOverviewState';
import { buildRealtimeSourceDisplay } from '@/features/monitoring/realtimeSourceDisplay';
import { buildCacheTokenPresentation } from '@/features/monitoring/components/accountOverviewPresentation';

const t = ((key: string, options?: Record<string, unknown>) => {
const copy: Record<string, string> = {
Expand Down Expand Up @@ -269,6 +270,33 @@ describe('MonitoringCenterPage summary cards', () => {
});

describe('MonitoringCenterPage account card', () => {
it('formats legacy and fine-grained account cache metrics without changing the token slot', () => {
expect(
buildCacheTokenPresentation(
{ cachedTokens: 12_500, cacheReadTokens: 0, cacheCreationTokens: 0 },
t
)
).toMatchObject({ label: 'Cached Tokens', value: '12.5K' });
expect(
buildCacheTokenPresentation(
{ cachedTokens: 0, cacheReadTokens: 1_200, cacheCreationTokens: 300 },
t
)
).toMatchObject({ label: 'CR / CW', value: '1.2K / 300' });
expect(
buildCacheTokenPresentation(
{ cachedTokens: 40, cacheReadTokens: 1_200, cacheCreationTokens: 300 },
t
)
).toMatchObject({ label: 'C / CR / CW', value: '40 / 1.2K / 300' });
expect(
buildCacheTokenPresentation(
{ cachedTokens: 0, cacheReadTokens: 0, cacheCreationTokens: 0 },
t
)
).toMatchObject({ label: 'Cached Tokens', value: '0' });
});

it('prefers readable channel names in realtime source cells', () => {
const display = buildRealtimeSourceDisplay(
{
Expand Down Expand Up @@ -688,7 +716,13 @@ describe('MonitoringCenterPage account card', () => {
{ key: 'total-tokens', label: 'Total Tokens', value: '35.1M' },
{ key: 'input-tokens', label: 'Input Tokens', value: '35.0M' },
{ key: 'output-tokens', label: 'Output Tokens', value: '68.5K' },
{ key: 'cached-tokens', label: 'Cached Tokens', value: '33.9M' },
{
key: 'cached-tokens',
label: 'C / CR / CW',
fullLabel:
'Cached Tokens: 33.9M · Cache Read Tokens: 1.2M · Cache Creation Tokens: 340.0K',
value: '33.9M / 1.2M / 340.0K',
},
]}
onRefreshQuota={() => {}}
variant="table"
Expand All @@ -698,9 +732,8 @@ describe('MonitoringCenterPage account card', () => {
expect(html).toContain('Token Structure');
expect(html).toContain('Input Tokens');
expect(html).toContain('Output Tokens');
expect(html).toContain('Cached Tokens');
expect(html).not.toContain('Cache Read Tokens');
expect(html).not.toContain('Cache Creation Tokens');
expect(html).toContain('C / CR / CW');
expect(html).toContain('33.9M / 1.2M / 340.0K');
expect(html).toContain('Model Usage Top 2');
expect(html).toContain('View All');
expect(html).not.toContain('<th>Read</th>');
Expand All @@ -709,6 +742,7 @@ describe('MonitoringCenterPage account card', () => {
expect(html).toContain('<th>Latest request</th>');
expect(html).toContain('gpt-5.5');
expect(html).toContain('codex-auto-review');
expect(html).toContain('C / CR / CW 32.5M / 1.1M / 300.0K');
expect(html).not.toContain('long-tail-model');
});

Expand Down
60 changes: 33 additions & 27 deletions apps/web/src/features/monitoring/components/AccountOverviewCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { MonitoringHealthStatusBar } from './MonitoringHealthStatusBar';
import {
buildAccountSecondaryText,
buildAccountSummaryMetrics,
buildCacheTokenPresentation,
formatPercent,
getAccountStatusDotClassName,
getAccountStatusLabel,
Expand Down Expand Up @@ -595,6 +596,7 @@ function AccountModelUsageList({
{visibleModels.map((model) => {
const modelKey = `${row.id}-${model.model}`;
const isModelExpanded = Boolean(expandedModels[modelKey]);
const cacheMetric = buildCacheTokenPresentation(model, t);
return (
<div key={modelKey} className={styles.accountModelItem}>
<button
Expand Down Expand Up @@ -653,14 +655,8 @@ function AccountModelUsageList({
<strong>{formatCompactNumber(model.outputTokens)}</strong>
</div>
<div className={styles.accountModelExpandedItem}>
<small>
{shortLabel(
t,
'monitoring.cached_tokens_short',
'monitoring.cached_tokens'
)}
</small>
<strong>{formatCompactNumber(model.cachedTokens)}</strong>
<small title={cacheMetric.fullLabel}>{cacheMetric.label}</small>
<strong>{cacheMetric.value}</strong>
</div>
<div className={styles.accountModelExpandedItem}>
<small>
Expand Down Expand Up @@ -743,25 +739,35 @@ export function AccountModelUsageTable({
</tr>
</thead>
<tbody>
{visibleModels.map((model) => (
<tr key={`${row.id}-${model.model}`}>
<td>
<span className={styles.accountModelName} title={model.model}>
{model.model}
</span>
</td>
<td>{formatCompactNumber(model.totalCalls)}</td>
<td className={getSuccessRateClassName(model.successRate)}>
{formatPercent(model.successRate)}
</td>
<td>{formatCompactNumber(model.inputTokens)}</td>
<td>{formatCompactNumber(model.outputTokens)}</td>
<td>{formatCompactNumber(model.cachedTokens)}</td>
<td>{formatCompactNumber(model.totalTokens)}</td>
<td>{hasPrices ? formatUsd(model.totalCost) : '--'}</td>
<td>{new Date(model.lastSeenAt).toLocaleString(locale)}</td>
</tr>
))}
{visibleModels.map((model) => {
const cacheMetric = buildCacheTokenPresentation(model, t);
return (
<tr key={`${row.id}-${model.model}`}>
<td>
<span className={styles.accountModelName} title={model.model}>
{model.model}
</span>
</td>
<td>{formatCompactNumber(model.totalCalls)}</td>
<td className={getSuccessRateClassName(model.successRate)}>
{formatPercent(model.successRate)}
</td>
<td>{formatCompactNumber(model.inputTokens)}</td>
<td>{formatCompactNumber(model.outputTokens)}</td>
<td>
<span title={cacheMetric.fullLabel}>
{cacheMetric.label ===
shortLabel(t, 'monitoring.cached_tokens_short', 'monitoring.cached_tokens')
? cacheMetric.value
: `${cacheMetric.label} ${cacheMetric.value}`}
</span>
</td>
<td>{formatCompactNumber(model.totalTokens)}</td>
<td>{hasPrices ? formatUsd(model.totalCost) : '--'}</td>
<td>{new Date(model.lastSeenAt).toLocaleString(locale)}</td>
</tr>
);
})}
</tbody>
</table>
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ export type AccountSummaryMetric = {
valueClassName?: string;
};

export type CacheTokenPresentation = {
label: string;
fullLabel: string;
value: string;
};

export const formatPercent = (value: number) => `${(value * 100).toFixed(1)}%`;

const joinShort = (values: string[], limit = 2) => {
Expand All @@ -65,6 +71,61 @@ const shortLabel = (t: TFunction, shortKey: string, fallbackKey: string) => {
return label === shortKey ? fallback : label;
};

export const buildCacheTokenPresentation = (
tokens: Pick<MonitoringAccountRow, 'cachedTokens' | 'cacheReadTokens' | 'cacheCreationTokens'>,
t: TFunction
): CacheTokenPresentation => {
const cachedTokens = Math.max(tokens.cachedTokens || 0, 0);
const cacheReadTokens = Math.max(tokens.cacheReadTokens || 0, 0);
const cacheCreationTokens = Math.max(tokens.cacheCreationTokens || 0, 0);
const hasFineGrainedCache = cacheReadTokens > 0 || cacheCreationTokens > 0;

if (!hasFineGrainedCache) {
return {
label: shortLabel(t, 'monitoring.cached_tokens_short', 'monitoring.cached_tokens'),
fullLabel: t('monitoring.cached_tokens'),
value: formatCompactNumber(cachedTokens),
};
}

const parts = [
cachedTokens > 0
? { code: 'C', fullLabel: t('monitoring.cached_tokens'), value: cachedTokens }
: null,
cacheReadTokens > 0
? { code: 'CR', fullLabel: t('monitoring.cache_read_tokens'), value: cacheReadTokens }
: null,
cacheCreationTokens > 0
? {
code: 'CW',
fullLabel: t('monitoring.cache_creation_tokens'),
value: cacheCreationTokens,
}
: null,
].filter((part): part is { code: string; fullLabel: string; value: number } => part !== null);

return {
label: parts.map((part) => part.code).join(' / '),
fullLabel: parts
.map((part) => `${part.fullLabel}: ${formatCompactNumber(part.value)}`)
.join(' · '),
value: parts.map((part) => formatCompactNumber(part.value)).join(' / '),
};
};

const buildAccountCacheSummaryMetric = (
row: MonitoringAccountRow,
t: TFunction
): AccountSummaryMetric => {
const cacheMetric = buildCacheTokenPresentation(row, t);
return {
key: 'cached-tokens',
label: cacheMetric.label,
fullLabel: cacheMetric.fullLabel,
value: cacheMetric.value,
};
};

export const getCodexPlanLabel = (
planType: string | null | undefined,
t: TFunction
Expand Down Expand Up @@ -144,12 +205,7 @@ export const buildAccountSummaryMetrics = (
fullLabel: t('monitoring.output_tokens'),
value: formatCompactNumber(row.outputTokens),
},
{
key: 'cached-tokens',
label: shortLabel(t, 'monitoring.cached_tokens_short', 'monitoring.cached_tokens'),
fullLabel: t('monitoring.cached_tokens'),
value: formatCompactNumber(row.cachedTokens),
},
buildAccountCacheSummaryMetric(row, t),
{
key: 'cache-creation-tokens',
label: shortLabel(
Expand Down
Loading