fix(patch): cherry-pick 54de675 to release/v0.20.0-pr-14961 [CONFLICTS]#14967
Conversation
…quota is present. (#14961) # Conflicts: # packages/cli/src/ui/components/StatsDisplay.test.tsx # packages/cli/src/ui/components/StatsDisplay.tsx # packages/cli/src/ui/components/__snapshots__/StatsDisplay.test.tsx.snap
Summary of ChangesHello @gemini-cli-robot, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request is an automated cherry-pick that aims to significantly improve the clarity and comprehensiveness of the model statistics display within the CLI. It introduces a more granular breakdown of token usage, distinguishing between uncached input and cache reads, and integrates user quota information directly into the model usage table. These changes provide users with a more precise understanding of their token consumption and remaining allowances, although merge conflicts require manual resolution. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request cherry-picks changes to improve the UI for displaying model and session statistics. The changes include relabeling metrics for clarity (e.g., "Prompt" to "Input", "Cached" to "Cache Reads"), adjusting calculations for token counts, and refactoring the stats table to conditionally display information based on available quota data. However, the cherry-pick has resulted in several unresolved merge conflicts across multiple files, including StatsDisplay.tsx, StatsDisplay.test.tsx, and its snapshot. These conflicts introduce markers like <<<<<<< HEAD into the code, which will cause build failures and must be resolved before this PR can be merged.
| <<<<<<< HEAD | ||
| expect(output).not.toContain('Efficiency & Optimizations'); | ||
| expect(output).not.toContain('Model'); // The table header | ||
| ======= | ||
| >>>>>>> 54de67536 (feat(cli): polish cached token stats and simplify stats display when quota is present. (#14961)) |
| <<<<<<< HEAD | ||
| ======= | ||
| // Logic for building the unified list of table rows | ||
| const buildModelRows = ( | ||
| models: Record<string, ModelMetrics>, | ||
| quotas?: RetrieveUserQuotaResponse, | ||
| ) => { | ||
| const getBaseModelName = (name: string) => name.replace('-001', ''); | ||
| const usedModelNames = new Set(Object.keys(models).map(getBaseModelName)); | ||
|
|
||
| // 1. Models with active usage | ||
| 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); | ||
| return { | ||
| key: name, | ||
| modelName, | ||
| requests: metrics.api.totalRequests, | ||
| cachedTokens: cachedTokens.toLocaleString(), | ||
| uncachedTokens: uncachedTokens.toLocaleString(), | ||
| totalInputTokens: totalInputTokens.toLocaleString(), | ||
| outputTokens: metrics.tokens.candidates.toLocaleString(), | ||
| bucket: quotas?.buckets?.find((b) => b.modelId === modelName), | ||
| isActive: true, | ||
| }; | ||
| }); | ||
|
|
||
| // 2. Models with quota only | ||
| const quotaRows = | ||
| quotas?.buckets | ||
| ?.filter( | ||
| (b) => | ||
| b.modelId && | ||
| VALID_GEMINI_MODELS.has(b.modelId) && | ||
| !usedModelNames.has(b.modelId), | ||
| ) | ||
| .map((bucket) => ({ | ||
| key: bucket.modelId!, | ||
| modelName: bucket.modelId!, | ||
| requests: '-', | ||
| cachedTokens: '-', | ||
| uncachedTokens: '-', | ||
| totalInputTokens: '-', | ||
| outputTokens: '-', | ||
| bucket, | ||
| isActive: false, | ||
| })) || []; | ||
|
|
||
| return [...activeRows, ...quotaRows]; | ||
| }; | ||
|
|
||
| >>>>>>> 54de67536 (feat(cli): polish cached token stats and simplify stats display when quota is present. (#14961)) |
There was a problem hiding this comment.
| <<<<<<< HEAD | ||
| }> = ({ models, totalCachedTokens, cacheEfficiency, quotas }) => { | ||
| ======= | ||
| cacheEfficiency: number; | ||
| totalCachedTokens: number; | ||
| }> = ({ models, quotas, cacheEfficiency, totalCachedTokens }) => { | ||
| const rows = buildModelRows(models, quotas); | ||
|
|
||
| if (rows.length === 0) { | ||
| return null; | ||
| } | ||
|
|
||
| const showQuotaColumn = !!quotas && rows.some((row) => !!row.bucket); | ||
|
|
||
| >>>>>>> 54de67536 (feat(cli): polish cached token stats and simplify stats display when quota is present. (#14961)) |
| width="100%" | ||
| ></Box> | ||
|
|
||
| <<<<<<< HEAD |
| ======= | ||
| {rows.map((row) => ( | ||
| <Box key={row.key}> | ||
| <Box width={nameWidth} flexGrow={1}> | ||
| <Text color={theme.text.primary} wrap="truncate-end"> | ||
| {row.modelName} | ||
| </Text> | ||
| </Box> | ||
| <Box | ||
| width={requestsWidth} | ||
| flexDirection="column" | ||
| alignItems="flex-end" | ||
| flexShrink={0} | ||
| > | ||
| <Text | ||
| color={row.isActive ? theme.text.primary : theme.text.secondary} | ||
| > | ||
| {row.requests} | ||
| </Text> | ||
| </Box> | ||
| {!showQuotaColumn && ( | ||
| <> | ||
| <Box | ||
| width={uncachedWidth} | ||
| flexDirection="column" | ||
| alignItems="flex-end" | ||
| flexShrink={0} | ||
| > | ||
| <Text | ||
| color={ | ||
| row.isActive ? theme.text.primary : theme.text.secondary | ||
| } | ||
| > | ||
| {row.uncachedTokens} | ||
| </Text> | ||
| </Box> | ||
| <Box | ||
| width={cachedWidth} | ||
| flexDirection="column" | ||
| alignItems="flex-end" | ||
| flexShrink={0} | ||
| > | ||
| <Text color={theme.text.secondary}>{row.cachedTokens}</Text> | ||
| </Box> | ||
| <Box | ||
| width={outputTokensWidth} | ||
| flexDirection="column" | ||
| alignItems="flex-end" | ||
| flexShrink={0} | ||
| > | ||
| <Text | ||
| color={ | ||
| row.isActive ? theme.text.primary : theme.text.secondary | ||
| } | ||
| > | ||
| {row.outputTokens} | ||
| </Text> | ||
| </Box> | ||
| </> | ||
| )} | ||
| <Box | ||
| width={usageLimitWidth} | ||
| flexDirection="column" | ||
| alignItems="flex-end" | ||
| > | ||
| {row.bucket && | ||
| row.bucket.remainingFraction != null && | ||
| row.bucket.resetTime && ( | ||
| <Text color={theme.text.secondary} wrap="truncate-end"> | ||
| {(row.bucket.remainingFraction * 100).toFixed(1)}%{' '} | ||
| {formatResetTime(row.bucket.resetTime)} | ||
| </Text> | ||
| )} | ||
| </Box> | ||
| </Box> | ||
| ))} | ||
|
|
||
| {cacheEfficiency > 0 && !showQuotaColumn && ( | ||
| >>>>>>> 54de67536 (feat(cli): polish cached token stats and simplify stats display when quota is present. (#14961)) |
| <<<<<<< HEAD | ||
| {models && ( | ||
| ======= | ||
|
|
||
| {showQuotaColumn && ( | ||
| >>>>>>> 54de67536 (feat(cli): polish cached token stats and simplify stats display when quota is present. (#14961)) |
| </Text> | ||
| </SubStatRow> | ||
| </Section> | ||
| <<<<<<< HEAD |
| ======= | ||
| <ModelUsageTable | ||
| models={models} | ||
| quotas={quotas} | ||
| cacheEfficiency={computed.cacheEfficiency} | ||
| totalCachedTokens={computed.totalCachedTokens} | ||
| /> | ||
| >>>>>>> 54de67536 (feat(cli): polish cached token stats and simplify stats display when quota is present. (#14961)) |
| <<<<<<< HEAD | ||
| ======= | ||
| exports[`<StatsDisplay /> > Quota Display > renders quota information for unused models 1`] = ` | ||
| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ | ||
| │ │ | ||
| │ Session Stats │ | ||
| │ │ | ||
| │ Interaction Summary │ | ||
| │ Session ID: test-session-id │ | ||
| │ Tool Calls: 0 ( ✓ 0 x 0 ) │ | ||
| │ Success Rate: 0.0% │ | ||
| │ │ | ||
| │ Performance │ | ||
| │ Wall Time: 1s │ | ||
| │ Agent Active: 0s │ | ||
| │ » API Time: 0s (0.0%) │ | ||
| │ » Tool Time: 0s (0.0%) │ | ||
| │ │ | ||
| │ │ | ||
| │ Model Usage Reqs Usage left │ | ||
| │ ────────────────────────────────────────────────────────────────────────────────────────────── │ | ||
| │ gemini-2.5-flash - 50.0% (Resets in 2h) │ | ||
| │ │ | ||
| │ Usage limits span all sessions and reset daily. │ | ||
| │ /auth to upgrade or switch to API key. │ | ||
| │ │ | ||
| │ │ | ||
| │ » Tip: For a full token breakdown, run \`/stats model\`. │ | ||
| │ │ | ||
| ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯" | ||
| `; | ||
|
|
||
| >>>>>>> 54de67536 (feat(cli): polish cached token stats and simplify stats display when quota is present. (#14961)) |
|
Hi @gemini-cli-robot, thank you so much for your contribution to Gemini CLI! We really appreciate the time and effort you've put into this. We're making some updates to our contribution process to improve how we track and review changes. Please take a moment to review our recent discussion post: Improving Our Contribution Process & Introducing New Guidelines. Key Update: Starting January 26, 2026, the Gemini CLI project will require all pull requests to be associated with an existing issue. Any pull requests not linked to an issue by that date will be automatically closed. Thank you for your understanding and for being a part of our community! |
|
Hi there! Thank you for your contribution to Gemini CLI. We really appreciate the time and effort you've put into this pull request. To keep our backlog manageable and ensure we're focusing on current priorities, we are closing pull requests that haven't seen maintainer activity for 30 days. Currently, the team is prioritizing work associated with 🔒 maintainer only or help wanted issues. If you believe this change is still critical, please feel free to comment with updated details. Otherwise, we encourage contributors to focus on open issues labeled as help wanted. Thank you for your understanding! |
This PR automatically cherry-picks commit 54de675 to patch version v0.20.0 in the stable release to create version 0.20.1.
This cherry-pick resulted in merge conflicts that need manual resolution.
🔧 Next Steps:
📋 Files with conflicts:
The commit has been created with conflict markers for easier manual resolution.
🚨 Important: