mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-14 07:10:34 -07:00
Co-authored-by: Yuna Seol <yunaseol@google.com>
This commit is contained in:
@@ -13,10 +13,17 @@ import {
|
||||
calculateCacheHitRate,
|
||||
calculateErrorRate,
|
||||
} from '../utils/computeStats.js';
|
||||
import { useSessionStats } from '../contexts/SessionContext.js';
|
||||
import {
|
||||
useSessionStats,
|
||||
type ModelMetrics,
|
||||
} from '../contexts/SessionContext.js';
|
||||
import { Table, type Column } from './Table.js';
|
||||
import { useSettings } from '../contexts/SettingsContext.js';
|
||||
import { getDisplayString, isAutoModel } from '@google/gemini-cli-core';
|
||||
import {
|
||||
getDisplayString,
|
||||
isAutoModel,
|
||||
LlmRole,
|
||||
} from '@google/gemini-cli-core';
|
||||
import type { QuotaStats } from '../types.js';
|
||||
import { QuotaStatsInfo } from './QuotaStatsInfo.js';
|
||||
|
||||
@@ -25,9 +32,11 @@ interface StatRowData {
|
||||
isSection?: boolean;
|
||||
isSubtle?: boolean;
|
||||
// Dynamic keys for model values
|
||||
[key: string]: string | React.ReactNode | boolean | undefined;
|
||||
[key: string]: string | React.ReactNode | boolean | undefined | number;
|
||||
}
|
||||
|
||||
type RoleMetrics = NonNullable<NonNullable<ModelMetrics['roles']>[LlmRole]>;
|
||||
|
||||
interface ModelStatsDisplayProps {
|
||||
selectedAuthType?: string;
|
||||
userEmail?: string;
|
||||
@@ -81,6 +90,22 @@ export const ModelStatsDisplay: React.FC<ModelStatsDisplayProps> = ({
|
||||
([, metrics]) => metrics.tokens.cached > 0,
|
||||
);
|
||||
|
||||
const allRoles = [
|
||||
...new Set(
|
||||
activeModels.flatMap(([, metrics]) => Object.keys(metrics.roles ?? {})),
|
||||
),
|
||||
]
|
||||
.filter((role): role is LlmRole => {
|
||||
const validRoles: string[] = Object.values(LlmRole);
|
||||
return validRoles.includes(role);
|
||||
})
|
||||
.sort((a, b) => {
|
||||
if (a === b) return 0;
|
||||
if (a === LlmRole.MAIN) return -1;
|
||||
if (b === LlmRole.MAIN) return 1;
|
||||
return a.localeCompare(b);
|
||||
});
|
||||
|
||||
// Helper to create a row with values for each model
|
||||
const createRow = (
|
||||
metric: string,
|
||||
@@ -204,6 +229,60 @@ export const ModelStatsDisplay: React.FC<ModelStatsDisplayProps> = ({
|
||||
),
|
||||
);
|
||||
|
||||
// Roles Section
|
||||
if (allRoles.length > 0) {
|
||||
// Spacer
|
||||
rows.push({ metric: '' });
|
||||
rows.push({ metric: 'Roles', isSection: true });
|
||||
|
||||
allRoles.forEach((role) => {
|
||||
// Role Header Row
|
||||
const roleHeaderRow: StatRowData = {
|
||||
metric: role,
|
||||
isSection: true,
|
||||
color: theme.text.primary,
|
||||
};
|
||||
// We don't populate model values for the role header row
|
||||
rows.push(roleHeaderRow);
|
||||
|
||||
const addRoleMetric = (
|
||||
metric: string,
|
||||
getValue: (r: RoleMetrics) => string | React.ReactNode,
|
||||
) => {
|
||||
const row: StatRowData = {
|
||||
metric,
|
||||
isSubtle: true,
|
||||
};
|
||||
activeModels.forEach(([name, metrics]) => {
|
||||
const roleMetrics = metrics.roles?.[role];
|
||||
if (roleMetrics) {
|
||||
row[name] = getValue(roleMetrics);
|
||||
} else {
|
||||
row[name] = <Text color={theme.text.secondary}>-</Text>;
|
||||
}
|
||||
});
|
||||
rows.push(row);
|
||||
};
|
||||
|
||||
addRoleMetric('Requests', (r) => r.totalRequests.toLocaleString());
|
||||
addRoleMetric('Input', (r) => (
|
||||
<Text color={theme.text.primary}>
|
||||
{r.tokens.input.toLocaleString()}
|
||||
</Text>
|
||||
));
|
||||
addRoleMetric('Output', (r) => (
|
||||
<Text color={theme.text.primary}>
|
||||
{r.tokens.candidates.toLocaleString()}
|
||||
</Text>
|
||||
));
|
||||
addRoleMetric('Cache Reads', (r) => (
|
||||
<Text color={theme.text.secondary}>
|
||||
{r.tokens.cached.toLocaleString()}
|
||||
</Text>
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
const columns: Array<Column<StatRowData>> = [
|
||||
{
|
||||
key: 'metric',
|
||||
|
||||
Reference in New Issue
Block a user