mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-30 16:00:41 -07:00
Show raw input token counts in json output. (#15021)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
@@ -4,7 +4,7 @@ exports[`runNonInteractive > should emit appropriate error event in streaming JS
|
||||
"{"type":"init","timestamp":"<TIMESTAMP>","session_id":"test-session-id","model":"test-model"}
|
||||
{"type":"message","timestamp":"<TIMESTAMP>","role":"user","content":"Loop test"}
|
||||
{"type":"error","timestamp":"<TIMESTAMP>","severity":"warning","message":"Loop detected, stopping execution"}
|
||||
{"type":"result","timestamp":"<TIMESTAMP>","status":"success","stats":{"total_tokens":0,"input_tokens":0,"output_tokens":0,"duration_ms":<DURATION>,"tool_calls":0}}
|
||||
{"type":"result","timestamp":"<TIMESTAMP>","status":"success","stats":{"total_tokens":0,"input_tokens":0,"output_tokens":0,"cached":0,"input":0,"duration_ms":<DURATION>,"tool_calls":0}}
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -12,7 +12,7 @@ exports[`runNonInteractive > should emit appropriate error event in streaming JS
|
||||
"{"type":"init","timestamp":"<TIMESTAMP>","session_id":"test-session-id","model":"test-model"}
|
||||
{"type":"message","timestamp":"<TIMESTAMP>","role":"user","content":"Max turns test"}
|
||||
{"type":"error","timestamp":"<TIMESTAMP>","severity":"error","message":"Maximum session turns exceeded"}
|
||||
{"type":"result","timestamp":"<TIMESTAMP>","status":"success","stats":{"total_tokens":0,"input_tokens":0,"output_tokens":0,"duration_ms":<DURATION>,"tool_calls":0}}
|
||||
{"type":"result","timestamp":"<TIMESTAMP>","status":"success","stats":{"total_tokens":0,"input_tokens":0,"output_tokens":0,"cached":0,"input":0,"duration_ms":<DURATION>,"tool_calls":0}}
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -23,7 +23,7 @@ exports[`runNonInteractive > should emit appropriate events for streaming JSON o
|
||||
{"type":"tool_use","timestamp":"<TIMESTAMP>","tool_name":"testTool","tool_id":"tool-1","parameters":{"arg1":"value1"}}
|
||||
{"type":"tool_result","timestamp":"<TIMESTAMP>","tool_id":"tool-1","status":"success","output":"Tool executed successfully"}
|
||||
{"type":"message","timestamp":"<TIMESTAMP>","role":"assistant","content":"Final answer","delta":true}
|
||||
{"type":"result","timestamp":"<TIMESTAMP>","status":"success","stats":{"total_tokens":0,"input_tokens":0,"output_tokens":0,"duration_ms":<DURATION>,"tool_calls":0}}
|
||||
{"type":"result","timestamp":"<TIMESTAMP>","status":"success","stats":{"total_tokens":0,"input_tokens":0,"output_tokens":0,"cached":0,"input":0,"duration_ms":<DURATION>,"tool_calls":0}}
|
||||
"
|
||||
`;
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ describe('<ModelStatsDisplay />', () => {
|
||||
'gemini-2.5-pro': {
|
||||
api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
|
||||
tokens: {
|
||||
input: 10,
|
||||
prompt: 10,
|
||||
candidates: 20,
|
||||
total: 30,
|
||||
@@ -128,6 +129,7 @@ describe('<ModelStatsDisplay />', () => {
|
||||
'gemini-2.5-pro': {
|
||||
api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
|
||||
tokens: {
|
||||
input: 5,
|
||||
prompt: 10,
|
||||
candidates: 20,
|
||||
total: 30,
|
||||
@@ -139,6 +141,7 @@ describe('<ModelStatsDisplay />', () => {
|
||||
'gemini-2.5-flash': {
|
||||
api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 50 },
|
||||
tokens: {
|
||||
input: 5,
|
||||
prompt: 5,
|
||||
candidates: 10,
|
||||
total: 15,
|
||||
@@ -180,6 +183,7 @@ describe('<ModelStatsDisplay />', () => {
|
||||
'gemini-2.5-pro': {
|
||||
api: { totalRequests: 10, totalErrors: 1, totalLatencyMs: 1000 },
|
||||
tokens: {
|
||||
input: 50,
|
||||
prompt: 100,
|
||||
candidates: 200,
|
||||
total: 300,
|
||||
@@ -191,6 +195,7 @@ describe('<ModelStatsDisplay />', () => {
|
||||
'gemini-2.5-flash': {
|
||||
api: { totalRequests: 20, totalErrors: 2, totalLatencyMs: 500 },
|
||||
tokens: {
|
||||
input: 100,
|
||||
prompt: 200,
|
||||
candidates: 400,
|
||||
total: 600,
|
||||
@@ -235,6 +240,7 @@ describe('<ModelStatsDisplay />', () => {
|
||||
totalLatencyMs: 9876,
|
||||
},
|
||||
tokens: {
|
||||
input: 987654321 - 123456789,
|
||||
prompt: 987654321,
|
||||
candidates: 123456789,
|
||||
total: 999999999,
|
||||
@@ -272,6 +278,7 @@ describe('<ModelStatsDisplay />', () => {
|
||||
'gemini-2.5-pro': {
|
||||
api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
|
||||
tokens: {
|
||||
input: 5,
|
||||
prompt: 10,
|
||||
candidates: 20,
|
||||
total: 30,
|
||||
|
||||
@@ -170,7 +170,7 @@ export const ModelStatsDisplay: React.FC = () => {
|
||||
isSubtle
|
||||
values={getModelValues((m) => (
|
||||
<Text color={theme.text.primary}>
|
||||
{Math.max(0, m.tokens.prompt - m.tokens.cached).toLocaleString()}
|
||||
{m.tokens.input.toLocaleString()}
|
||||
</Text>
|
||||
))}
|
||||
/>
|
||||
|
||||
@@ -45,6 +45,7 @@ describe('<SessionSummaryDisplay />', () => {
|
||||
'gemini-2.5-pro': {
|
||||
api: { totalRequests: 10, totalErrors: 1, totalLatencyMs: 50234 },
|
||||
tokens: {
|
||||
input: 500,
|
||||
prompt: 1000,
|
||||
candidates: 2000,
|
||||
total: 3500,
|
||||
|
||||
@@ -85,6 +85,7 @@ describe('<StatsDisplay />', () => {
|
||||
'gemini-2.5-pro': {
|
||||
api: { totalRequests: 3, totalErrors: 0, totalLatencyMs: 15000 },
|
||||
tokens: {
|
||||
input: 500,
|
||||
prompt: 1000,
|
||||
candidates: 2000,
|
||||
total: 43234,
|
||||
@@ -96,6 +97,7 @@ describe('<StatsDisplay />', () => {
|
||||
'gemini-2.5-flash': {
|
||||
api: { totalRequests: 5, totalErrors: 1, totalLatencyMs: 4500 },
|
||||
tokens: {
|
||||
input: 15000,
|
||||
prompt: 25000,
|
||||
candidates: 15000,
|
||||
total: 150000000,
|
||||
@@ -123,6 +125,7 @@ describe('<StatsDisplay />', () => {
|
||||
'gemini-2.5-pro': {
|
||||
api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
|
||||
tokens: {
|
||||
input: 50,
|
||||
prompt: 100,
|
||||
candidates: 100,
|
||||
total: 250,
|
||||
@@ -216,6 +219,7 @@ describe('<StatsDisplay />', () => {
|
||||
'gemini-2.5-pro': {
|
||||
api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
|
||||
tokens: {
|
||||
input: 100,
|
||||
prompt: 100,
|
||||
candidates: 100,
|
||||
total: 200,
|
||||
@@ -398,6 +402,7 @@ describe('<StatsDisplay />', () => {
|
||||
'gemini-2.5-pro': {
|
||||
api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
|
||||
tokens: {
|
||||
input: 50,
|
||||
prompt: 100,
|
||||
candidates: 100,
|
||||
total: 250,
|
||||
|
||||
@@ -85,15 +85,13 @@ const buildModelRows = (
|
||||
const activeRows = Object.entries(models).map(([name, metrics]) => {
|
||||
const modelName = getBaseModelName(name);
|
||||
const cachedTokens = metrics.tokens.cached;
|
||||
const totalInputTokens = metrics.tokens.prompt;
|
||||
const uncachedTokens = Math.max(0, totalInputTokens - cachedTokens);
|
||||
const inputTokens = metrics.tokens.input;
|
||||
return {
|
||||
key: name,
|
||||
modelName,
|
||||
requests: metrics.api.totalRequests,
|
||||
cachedTokens: cachedTokens.toLocaleString(),
|
||||
uncachedTokens: uncachedTokens.toLocaleString(),
|
||||
totalInputTokens: totalInputTokens.toLocaleString(),
|
||||
inputTokens: inputTokens.toLocaleString(),
|
||||
outputTokens: metrics.tokens.candidates.toLocaleString(),
|
||||
bucket: quotas?.buckets?.find((b) => b.modelId === modelName),
|
||||
isActive: true,
|
||||
@@ -114,8 +112,7 @@ const buildModelRows = (
|
||||
modelName: bucket.modelId!,
|
||||
requests: '-',
|
||||
cachedTokens: '-',
|
||||
uncachedTokens: '-',
|
||||
totalInputTokens: '-',
|
||||
inputTokens: '-',
|
||||
outputTokens: '-',
|
||||
bucket,
|
||||
isActive: false,
|
||||
@@ -290,7 +287,7 @@ const ModelUsageTable: React.FC<{
|
||||
row.isActive ? theme.text.primary : theme.text.secondary
|
||||
}
|
||||
>
|
||||
{row.uncachedTokens}
|
||||
{row.inputTokens}
|
||||
</Text>
|
||||
</Box>
|
||||
<Box
|
||||
|
||||
@@ -92,6 +92,7 @@ describe('SessionStatsContext', () => {
|
||||
totalLatencyMs: 123,
|
||||
},
|
||||
tokens: {
|
||||
input: 50,
|
||||
prompt: 100,
|
||||
candidates: 200,
|
||||
total: 300,
|
||||
@@ -171,6 +172,7 @@ describe('SessionStatsContext', () => {
|
||||
'gemini-pro': {
|
||||
api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
|
||||
tokens: {
|
||||
input: 10,
|
||||
prompt: 10,
|
||||
candidates: 20,
|
||||
total: 30,
|
||||
@@ -212,6 +214,7 @@ describe('SessionStatsContext', () => {
|
||||
'gemini-pro': {
|
||||
api: { totalRequests: 2, totalErrors: 0, totalLatencyMs: 200 },
|
||||
tokens: {
|
||||
input: 20,
|
||||
prompt: 20,
|
||||
candidates: 40,
|
||||
total: 60,
|
||||
|
||||
@@ -37,6 +37,7 @@ function areModelMetricsEqual(a: ModelMetrics, b: ModelMetrics): boolean {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
a.tokens.input !== b.tokens.input ||
|
||||
a.tokens.prompt !== b.tokens.prompt ||
|
||||
a.tokens.candidates !== b.tokens.candidates ||
|
||||
a.tokens.total !== b.tokens.total ||
|
||||
@@ -159,6 +160,7 @@ export interface ComputedSessionStats {
|
||||
successRate: number;
|
||||
agreementRate: number;
|
||||
totalCachedTokens: number;
|
||||
totalInputTokens: number;
|
||||
totalPromptTokens: number;
|
||||
totalLinesAdded: number;
|
||||
totalLinesRemoved: number;
|
||||
|
||||
@@ -21,6 +21,7 @@ describe('calculateErrorRate', () => {
|
||||
const metrics: ModelMetrics = {
|
||||
api: { totalRequests: 0, totalErrors: 0, totalLatencyMs: 0 },
|
||||
tokens: {
|
||||
input: 0,
|
||||
prompt: 0,
|
||||
candidates: 0,
|
||||
total: 0,
|
||||
@@ -36,6 +37,7 @@ describe('calculateErrorRate', () => {
|
||||
const metrics: ModelMetrics = {
|
||||
api: { totalRequests: 10, totalErrors: 2, totalLatencyMs: 0 },
|
||||
tokens: {
|
||||
input: 0,
|
||||
prompt: 0,
|
||||
candidates: 0,
|
||||
total: 0,
|
||||
@@ -53,6 +55,7 @@ describe('calculateAverageLatency', () => {
|
||||
const metrics: ModelMetrics = {
|
||||
api: { totalRequests: 0, totalErrors: 0, totalLatencyMs: 1000 },
|
||||
tokens: {
|
||||
input: 0,
|
||||
prompt: 0,
|
||||
candidates: 0,
|
||||
total: 0,
|
||||
@@ -68,6 +71,7 @@ describe('calculateAverageLatency', () => {
|
||||
const metrics: ModelMetrics = {
|
||||
api: { totalRequests: 10, totalErrors: 0, totalLatencyMs: 1500 },
|
||||
tokens: {
|
||||
input: 0,
|
||||
prompt: 0,
|
||||
candidates: 0,
|
||||
total: 0,
|
||||
@@ -85,6 +89,7 @@ describe('calculateCacheHitRate', () => {
|
||||
const metrics: ModelMetrics = {
|
||||
api: { totalRequests: 0, totalErrors: 0, totalLatencyMs: 0 },
|
||||
tokens: {
|
||||
input: 0,
|
||||
prompt: 0,
|
||||
candidates: 0,
|
||||
total: 0,
|
||||
@@ -100,6 +105,7 @@ describe('calculateCacheHitRate', () => {
|
||||
const metrics: ModelMetrics = {
|
||||
api: { totalRequests: 0, totalErrors: 0, totalLatencyMs: 0 },
|
||||
tokens: {
|
||||
input: 150,
|
||||
prompt: 200,
|
||||
candidates: 0,
|
||||
total: 0,
|
||||
@@ -143,6 +149,7 @@ describe('computeSessionStats', () => {
|
||||
successRate: 0,
|
||||
agreementRate: 0,
|
||||
totalPromptTokens: 0,
|
||||
totalInputTokens: 0,
|
||||
totalCachedTokens: 0,
|
||||
totalLinesAdded: 0,
|
||||
totalLinesRemoved: 0,
|
||||
@@ -155,6 +162,7 @@ describe('computeSessionStats', () => {
|
||||
'gemini-pro': {
|
||||
api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 750 },
|
||||
tokens: {
|
||||
input: 10,
|
||||
prompt: 10,
|
||||
candidates: 10,
|
||||
total: 20,
|
||||
@@ -193,6 +201,7 @@ describe('computeSessionStats', () => {
|
||||
'gemini-pro': {
|
||||
api: { totalRequests: 2, totalErrors: 0, totalLatencyMs: 1000 },
|
||||
tokens: {
|
||||
input: 100,
|
||||
prompt: 150,
|
||||
candidates: 10,
|
||||
total: 160,
|
||||
|
||||
@@ -50,6 +50,10 @@ export const computeSessionStats = (
|
||||
(acc, model) => acc + model.tokens.cached,
|
||||
0,
|
||||
);
|
||||
const totalInputTokens = Object.values(models).reduce(
|
||||
(acc, model) => acc + model.tokens.input,
|
||||
0,
|
||||
);
|
||||
const totalPromptTokens = Object.values(models).reduce(
|
||||
(acc, model) => acc + model.tokens.prompt,
|
||||
0,
|
||||
@@ -82,6 +86,7 @@ export const computeSessionStats = (
|
||||
successRate,
|
||||
agreementRate,
|
||||
totalCachedTokens,
|
||||
totalInputTokens,
|
||||
totalPromptTokens,
|
||||
totalLinesAdded: files.totalLinesAdded,
|
||||
totalLinesRemoved: files.totalLinesRemoved,
|
||||
|
||||
@@ -47,7 +47,15 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
})),
|
||||
StreamJsonFormatter: vi.fn().mockImplementation(() => ({
|
||||
emitEvent: vi.fn(),
|
||||
convertToStreamStats: vi.fn().mockReturnValue({}),
|
||||
convertToStreamStats: vi.fn().mockReturnValue({
|
||||
total_tokens: 0,
|
||||
input_tokens: 0,
|
||||
output_tokens: 0,
|
||||
cached: 0,
|
||||
input: 0,
|
||||
duration_ms: 0,
|
||||
tool_calls: 0,
|
||||
}),
|
||||
})),
|
||||
uiTelemetryService: {
|
||||
getMetrics: vi.fn().mockReturnValue({}),
|
||||
|
||||
Reference in New Issue
Block a user