Skip to content

feat: add Gemini 3.1 Pro pricing and model aliases#125

Merged
mike1858 merged 6 commits intomainfrom
feat/gemini-3.1-pro-pricing
Mar 12, 2026
Merged

feat: add Gemini 3.1 Pro pricing and model aliases#125
mike1858 merged 6 commits intomainfrom
feat/gemini-3.1-pro-pricing

Conversation

@mike1858
Copy link
Member

@mike1858 mike1858 commented Feb 28, 2026

Add pricing data and model aliases for Gemini 3.1 Pro Preview.

  • Tiered pricing: $2.00/$12.00 per 1M tokens (≤200k), $4.00/$18.00 (>200k)
  • Google-style caching tiers: $0.20 (≤200k), $0.40 (>200k)
  • Aliases: gemini-3.1-pro-preview, gemini-3.1-pro

Summary by CodeRabbit

  • New Features
    • Added tiered pricing and tiered caching with optional bracket-based billing; introduced Gemini 3.1 Pro Preview with bracketed tiers and updated model pricing/aliases.
  • Bug Fixes
    • Prevented duplicated assistant messages in CLI JSONL parsing when token-usage events occur.
  • Tests
    • Added unit tests for bracket-pricing behavior and progressive tier calculations.
  • Chores
    • Updated a dependency version and removed an unused dependency.

@coderabbitai
Copy link

coderabbitai bot commented Feb 28, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Introduced TieredPricing and TieredCaching wrappers with bracket_pricing semantics; migrated tiered pricing/caching variants to use them and updated many model entries (including gemini-3.1-pro-preview). Threaded bracket_pricing through cost calculations and tests. Added a Codex CLI guard to avoid duplicate assistant emits, a comment tweak in Copilot analyzer, and small dependency updates.

Changes

Cohort / File(s) Summary
Model configuration
src/models.rs
Added TieredPricing and TieredCaching (public); changed PricingStructure::TieredTiered(TieredPricing) and CachingSupport::GoogleGoogle(TieredCaching); threaded bracket_pricing through cost calculations, added find_tier logic, updated MODEL_INDEX entries (e.g., gemini-3.1-pro-preview), adjusted is_estimated flags, and added unit tests for bracket/progressive pricing.
Codex CLI parser
src/analyzers/codex_cli.rs
Guarded emission of assistant message with if !saw_token_usage to prevent duplicate assistant output when token-usage events exist.
Copilot analyzer (comments)
src/analyzers/copilot.rs
Minor comment moved/added inside extract_text_from_value; behavior unchanged.
Manifest / deps
Cargo.toml
Removed bincode dependency; bumped reqwest from 0.13.10.13.2.

Sequence Diagram(s)

(omitted — changes are primarily data-structure and calculation refactors plus small parser guard)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐇 I hopped through tiers with whiskers bright,
Bracketed carrots counted just right.
Gemini seeds and caching dreams,
Codex hushes twin-like streams.
A joyful thump — the pricing gleams.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 61.54% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main changes: adding Gemini 3.1 Pro pricing data and model aliases, which is the primary purpose of the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/gemini-3.1-pro-pricing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

- Tiered pricing: $2.00/$12.00 per 1M tokens (≤200k), $4.00/$18.00 (>200k)
- Google-style caching tiers: $0.20 (≤200k), $0.40 (>200k)
- Aliases: gemini-3.1-pro-preview, gemini-3.1-pro
- Fix pre-existing clippy::collapsible_match warnings
@mike1858 mike1858 force-pushed the feat/gemini-3.1-pro-pricing branch from e844043 to 7588e48 Compare February 28, 2026 00:53
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/models.rs (1)

1008-1009: Add a regression test for the new aliases.

A small table-driven test for get_model_info("gemini-3.1-pro") and get_model_info("gemini-3.1-pro-preview") would lock down the alias mapping and catch future pricing drift around this entry.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/models.rs` around lines 1008 - 1009, Add a table-driven unit test that
calls get_model_info for both "gemini-3.1-pro" and "gemini-3.1-pro-preview" and
asserts they resolve to the same canonical model and expected pricing; place it
near other model tests (e.g., in the tests module or tests/ directory). The test
should iterate over inputs ["gemini-3.1-pro", "gemini-3.1-pro-preview"], call
get_model_info(input), assert the returned ModelInfo.id (or equivalent canonical
identifier) equals "gemini-3.1-pro-preview" (or the current canonical id used in
the mapping) and assert the pricing fields match the current expected values to
catch future drift. Use descriptive test name and table rows so future updates
can update expected price in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/models.rs`:
- Around line 538-566: The Gemini entry "gemini-3.1-pro-preview" is defined with
tiered pricing but the business intent is bracket pricing (charge the full usage
at the >200k rate), so either mark this model as bracketed and/or change the
pricing data and logic: add a bracket_pricing flag on PricingStructure or
PricingTier and set it for gemini-3.1-pro-preview, then update
calculate_tiered_cost() and calculate_tiered_cache_cost() to check that flag
and, when true, select the single tier whose range contains the total tokens and
multiply the entire usage by that tier's rate (instead of applying tiers
progressively). Ensure you update both PricingStructure::Tiered usage for
caching (CachingTier) and the model entry for gemini-3.1-pro-preview to use the
new flag so cache and non-cache calculations behave consistently.

---

Nitpick comments:
In `@src/models.rs`:
- Around line 1008-1009: Add a table-driven unit test that calls get_model_info
for both "gemini-3.1-pro" and "gemini-3.1-pro-preview" and asserts they resolve
to the same canonical model and expected pricing; place it near other model
tests (e.g., in the tests module or tests/ directory). The test should iterate
over inputs ["gemini-3.1-pro", "gemini-3.1-pro-preview"], call
get_model_info(input), assert the returned ModelInfo.id (or equivalent canonical
identifier) equals "gemini-3.1-pro-preview" (or the current canonical id used in
the mapping) and assert the pricing fields match the current expected values to
catch future drift. Use descriptive test name and table rows so future updates
can update expected price in one place.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 159cefb1-c2d3-40e0-8096-145c9fcc8462

📥 Commits

Reviewing files that changed from the base of the PR and between 13e7e92 and 744d989.

📒 Files selected for processing (1)
  • src/models.rs

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/models.rs`:
- Around line 1351-1364: The function signature for find_tier declares an
explicit lifetime ('a) that Clippy flags as needless; remove the explicit
lifetime parameter and let elision infer it by changing the signature to drop 'a
and use tiers: &[T] -> Option<&T> (keep the same parameters and the where clause
F: Fn(&T) -> Option<u64>), leaving the function body unchanged so references
compile with elided lifetimes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fd49b170-54d5-4d55-8f77-bd46173f4c31

📥 Commits

Reviewing files that changed from the base of the PR and between 744d989 and 2472ffa.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • Cargo.toml
  • src/models.rs

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/models.rs (1)

589-604: ⚠️ Potential issue | 🔴 Critical

Keep gemini-3-pro-preview-11-2025 bracketed and cache-priced too.

This entry still bills progressively and returns $0 cache cost, but Google's Gemini 3 Pro Preview pricing uses the same <=200k / >200k bracket rule for the whole request and includes non-zero context-caching rates. Since Lines 1044-1046 still route gemini-3-pro-preview and gemini-3-pro here, those aliases remain underbilled above 200k tokens and miss cache-read cost entirely. (ai.google.dev)

🔧 Proposed fix
     "gemini-3-pro-preview-11-2025" => ModelInfo {
         pricing: PricingStructure::Tiered(TieredPricing {
             tiers: &[
                 PricingTier {
                     max_tokens: Some(200_000),
                     input_per_1m: 2.0,
                     output_per_1m: 12.0,
                 },
                 PricingTier {
                     max_tokens: None,
                     input_per_1m: 4.0,
                     output_per_1m: 18.0,
                 },
             ],
-            bracket_pricing: false,
+            bracket_pricing: true,
         }),
-        caching: CachingSupport::None,
+        caching: CachingSupport::Google(TieredCaching {
+            tiers: &[
+                CachingTier {
+                    max_tokens: Some(200_000),
+                    cached_input_per_1m: 0.20,
+                },
+                CachingTier {
+                    max_tokens: None,
+                    cached_input_per_1m: 0.40,
+                },
+            ],
+            bracket_pricing: true,
+        }),
         is_estimated: false,
     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/models.rs` around lines 589 - 604, The gemini-3-pro-preview-11-2025 model
entry is missing bracket_pricing and non-zero caching rates: update the
PricingStructure::Tiered(TieredPricing { ... }) for the
gemini-3-pro-preview-11-2025 record so bracket_pricing is true (apply <=200k /
>200k whole-request brackets) and set CachingSupport from None to the proper
priced cache variant with non-zero cache read/write rates; modify the
PricingTier values accordingly (use same tiers as gemini-3-pro/3-pro-preview but
ensure caching fields are populated) so aliases gemini-3-pro-preview and
gemini-3-pro routed here are billed correctly.
🧹 Nitpick comments (1)
src/models.rs (1)

1374-1391: Add one alias-level regression test.

The new tests only exercise the canonical "gemini-3.1-pro-preview" name. A small assertion for "gemini-3.1-pro" would cover the PR's alias change and catch a typo here before it silently falls back to the unknown-model $0 path.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/models.rs` around lines 1374 - 1391, Add an alias-level regression test
to cover the canonical alias as well as the preview name: add a test that calls
calculate_input_cost("gemini-3.1-pro", 250_000) (and optionally
calculate_cache_cost("gemini-3.1-pro", 0, 250_000)) and assert the same expected
values as the existing gemini_3_1_pro_preview tests; this ensures the alias
mapping used by calculate_input_cost and calculate_cache_cost is exercised and
prevents silent fallback to the unknown-model path (refer to the existing test
functions gemini_3_1_pro_preview_uses_bracket_pricing_for_input and
gemini_3_1_pro_preview_uses_bracket_pricing_for_cache_reads for structure and
expected assertions).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/models.rs`:
- Around line 589-604: The gemini-3-pro-preview-11-2025 model entry is missing
bracket_pricing and non-zero caching rates: update the
PricingStructure::Tiered(TieredPricing { ... }) for the
gemini-3-pro-preview-11-2025 record so bracket_pricing is true (apply <=200k /
>200k whole-request brackets) and set CachingSupport from None to the proper
priced cache variant with non-zero cache read/write rates; modify the
PricingTier values accordingly (use same tiers as gemini-3-pro/3-pro-preview but
ensure caching fields are populated) so aliases gemini-3-pro-preview and
gemini-3-pro routed here are billed correctly.

---

Nitpick comments:
In `@src/models.rs`:
- Around line 1374-1391: Add an alias-level regression test to cover the
canonical alias as well as the preview name: add a test that calls
calculate_input_cost("gemini-3.1-pro", 250_000) (and optionally
calculate_cache_cost("gemini-3.1-pro", 0, 250_000)) and assert the same expected
values as the existing gemini_3_1_pro_preview tests; this ensures the alias
mapping used by calculate_input_cost and calculate_cache_cost is exercised and
prevents silent fallback to the unknown-model path (refer to the existing test
functions gemini_3_1_pro_preview_uses_bracket_pricing_for_input and
gemini_3_1_pro_preview_uses_bracket_pricing_for_cache_reads for structure and
expected assertions).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 676c7d2e-52ea-476a-8299-1e19393671cb

📥 Commits

Reviewing files that changed from the base of the PR and between 2472ffa and fc277dd.

📒 Files selected for processing (1)
  • src/models.rs

@mike1858 mike1858 merged commit 547ad6b into main Mar 12, 2026
6 checks passed
@mike1858 mike1858 deleted the feat/gemini-3.1-pro-pricing branch March 12, 2026 00:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant