mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-20 08:47:44 +00:00
feat: Change /stats to include more detailed breakdowns (#2615)
This commit is contained in:
208
packages/cli/src/ui/components/ToolStatsDisplay.tsx
Normal file
208
packages/cli/src/ui/components/ToolStatsDisplay.tsx
Normal file
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import { Colors } from '../colors.js';
|
||||
import { formatDuration } from '../utils/formatters.js';
|
||||
import {
|
||||
getStatusColor,
|
||||
TOOL_SUCCESS_RATE_HIGH,
|
||||
TOOL_SUCCESS_RATE_MEDIUM,
|
||||
USER_AGREEMENT_RATE_HIGH,
|
||||
USER_AGREEMENT_RATE_MEDIUM,
|
||||
} from '../utils/displayUtils.js';
|
||||
import { useSessionStats } from '../contexts/SessionContext.js';
|
||||
import { ToolCallStats } from '@google/gemini-cli-core';
|
||||
|
||||
const TOOL_NAME_COL_WIDTH = 25;
|
||||
const CALLS_COL_WIDTH = 8;
|
||||
const SUCCESS_RATE_COL_WIDTH = 15;
|
||||
const AVG_DURATION_COL_WIDTH = 15;
|
||||
|
||||
const StatRow: React.FC<{
|
||||
name: string;
|
||||
stats: ToolCallStats;
|
||||
}> = ({ name, stats }) => {
|
||||
const successRate = stats.count > 0 ? (stats.success / stats.count) * 100 : 0;
|
||||
const avgDuration = stats.count > 0 ? stats.durationMs / stats.count : 0;
|
||||
const successColor = getStatusColor(successRate, {
|
||||
green: TOOL_SUCCESS_RATE_HIGH,
|
||||
yellow: TOOL_SUCCESS_RATE_MEDIUM,
|
||||
});
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box width={TOOL_NAME_COL_WIDTH}>
|
||||
<Text color={Colors.LightBlue}>{name}</Text>
|
||||
</Box>
|
||||
<Box width={CALLS_COL_WIDTH} justifyContent="flex-end">
|
||||
<Text>{stats.count}</Text>
|
||||
</Box>
|
||||
<Box width={SUCCESS_RATE_COL_WIDTH} justifyContent="flex-end">
|
||||
<Text color={successColor}>{successRate.toFixed(1)}%</Text>
|
||||
</Box>
|
||||
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
|
||||
<Text>{formatDuration(avgDuration)}</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export const ToolStatsDisplay: React.FC = () => {
|
||||
const { stats } = useSessionStats();
|
||||
const { tools } = stats.metrics;
|
||||
const activeTools = Object.entries(tools.byName).filter(
|
||||
([, metrics]) => metrics.count > 0,
|
||||
);
|
||||
|
||||
if (activeTools.length === 0) {
|
||||
return (
|
||||
<Box
|
||||
borderStyle="round"
|
||||
borderColor={Colors.Gray}
|
||||
paddingY={1}
|
||||
paddingX={2}
|
||||
>
|
||||
<Text>No tool calls have been made in this session.</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
const totalDecisions = Object.values(tools.byName).reduce(
|
||||
(acc, tool) => {
|
||||
acc.accept += tool.decisions.accept;
|
||||
acc.reject += tool.decisions.reject;
|
||||
acc.modify += tool.decisions.modify;
|
||||
return acc;
|
||||
},
|
||||
{ accept: 0, reject: 0, modify: 0 },
|
||||
);
|
||||
|
||||
const totalReviewed =
|
||||
totalDecisions.accept + totalDecisions.reject + totalDecisions.modify;
|
||||
const agreementRate =
|
||||
totalReviewed > 0 ? (totalDecisions.accept / totalReviewed) * 100 : 0;
|
||||
const agreementColor = getStatusColor(agreementRate, {
|
||||
green: USER_AGREEMENT_RATE_HIGH,
|
||||
yellow: USER_AGREEMENT_RATE_MEDIUM,
|
||||
});
|
||||
|
||||
return (
|
||||
<Box
|
||||
borderStyle="round"
|
||||
borderColor={Colors.Gray}
|
||||
flexDirection="column"
|
||||
paddingY={1}
|
||||
paddingX={2}
|
||||
width={70}
|
||||
>
|
||||
<Text bold color={Colors.AccentPurple}>
|
||||
Tool Stats For Nerds
|
||||
</Text>
|
||||
<Box height={1} />
|
||||
|
||||
{/* Header */}
|
||||
<Box>
|
||||
<Box width={TOOL_NAME_COL_WIDTH}>
|
||||
<Text bold>Tool Name</Text>
|
||||
</Box>
|
||||
<Box width={CALLS_COL_WIDTH} justifyContent="flex-end">
|
||||
<Text bold>Calls</Text>
|
||||
</Box>
|
||||
<Box width={SUCCESS_RATE_COL_WIDTH} justifyContent="flex-end">
|
||||
<Text bold>Success Rate</Text>
|
||||
</Box>
|
||||
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
|
||||
<Text bold>Avg Duration</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Divider */}
|
||||
<Box
|
||||
borderStyle="single"
|
||||
borderBottom={true}
|
||||
borderTop={false}
|
||||
borderLeft={false}
|
||||
borderRight={false}
|
||||
width="100%"
|
||||
/>
|
||||
|
||||
{/* Tool Rows */}
|
||||
{activeTools.map(([name, stats]) => (
|
||||
<StatRow key={name} name={name} stats={stats as ToolCallStats} />
|
||||
))}
|
||||
|
||||
<Box height={1} />
|
||||
|
||||
{/* User Decision Summary */}
|
||||
<Text bold>User Decision Summary</Text>
|
||||
<Box>
|
||||
<Box
|
||||
width={TOOL_NAME_COL_WIDTH + CALLS_COL_WIDTH + SUCCESS_RATE_COL_WIDTH}
|
||||
>
|
||||
<Text color={Colors.LightBlue}>Total Reviewed Suggestions:</Text>
|
||||
</Box>
|
||||
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
|
||||
<Text>{totalReviewed}</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box>
|
||||
<Box
|
||||
width={TOOL_NAME_COL_WIDTH + CALLS_COL_WIDTH + SUCCESS_RATE_COL_WIDTH}
|
||||
>
|
||||
<Text> » Accepted:</Text>
|
||||
</Box>
|
||||
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
|
||||
<Text color={Colors.AccentGreen}>{totalDecisions.accept}</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box>
|
||||
<Box
|
||||
width={TOOL_NAME_COL_WIDTH + CALLS_COL_WIDTH + SUCCESS_RATE_COL_WIDTH}
|
||||
>
|
||||
<Text> » Rejected:</Text>
|
||||
</Box>
|
||||
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
|
||||
<Text color={Colors.AccentRed}>{totalDecisions.reject}</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box>
|
||||
<Box
|
||||
width={TOOL_NAME_COL_WIDTH + CALLS_COL_WIDTH + SUCCESS_RATE_COL_WIDTH}
|
||||
>
|
||||
<Text> » Modified:</Text>
|
||||
</Box>
|
||||
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
|
||||
<Text color={Colors.AccentYellow}>{totalDecisions.modify}</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Divider */}
|
||||
<Box
|
||||
borderStyle="single"
|
||||
borderBottom={true}
|
||||
borderTop={false}
|
||||
borderLeft={false}
|
||||
borderRight={false}
|
||||
width="100%"
|
||||
/>
|
||||
|
||||
<Box>
|
||||
<Box
|
||||
width={TOOL_NAME_COL_WIDTH + CALLS_COL_WIDTH + SUCCESS_RATE_COL_WIDTH}
|
||||
>
|
||||
<Text> Overall Agreement Rate:</Text>
|
||||
</Box>
|
||||
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
|
||||
<Text bold color={totalReviewed > 0 ? agreementColor : undefined}>
|
||||
{totalReviewed > 0 ? `${agreementRate.toFixed(1)}%` : '--'}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user