Skip to content

fix(llm): report zero cost for OpenRouter free-tier models - #613

Merged
ilblackdragon merged 1 commit into
nearai:mainfrom
guoqunabc:fix/openrouter-free-tier-costs
Mar 7, 2026
Merged

ilblackdragon merged 1 commit into
nearai:mainfrom
guoqunabc:fix/openrouter-free-tier-costs

Conversation

@guoqunabc

Copy link
Copy Markdown
Contributor

Problem

OpenRouter free-tier models report GPT-4o default pricing (~$2.50/$10.00 per 1M tokens) instead of $0 in the IronClaw UI.

Fixes #463.

Root Cause

model_cost() in src/llm/costs.rs normalizes model identifiers by stripping the provider prefix via rsplit_once("/"). For OpenRouter free-tier models this produces identifiers that don't match any entry in the cost table:

User-configured model After prefix strip Match?
stepfun/step-3.5-flash:free step-3.5-flash:free ❌ No match
openrouter/free free ❌ No match

Neither matches any known model name nor the is_local_model() heuristic, so they fall through to default_cost() — which returns GPT-4o pricing.

Fix

Add an early return before the prefix-stripping normalization that checks for:

  • The :free suffix (covers all provider/model:free patterns)
  • The literal openrouter/free and bare free identifiers

All matching models return (Decimal::ZERO, Decimal::ZERO).

The check is placed before prefix stripping intentionally — the :free suffix is part of the OpenRouter routing convention and would be lost or misinterpreted if we stripped first and matched later.

Tests

4 new test cases added:

  • test_openrouter_free_suffix_zero_cost — :free suffix model
  • test_openrouter_free_router_zero_cost — openrouter/free router
  • test_bare_free_zero_cost — edge case: bare free
  • test_free_suffix_various_providers — parametric test across 4 different provider-prefixed free models

Changes

  • src/llm/costs.rs: 6-line early return + 40 lines of tests

OpenRouter models with the `:free` suffix (e.g. `stepfun/step-3.5-flash:free`)
and the `openrouter/free` router were falling through to `default_cost()`,
which reports GPT-4o pricing (~$2.50/$10.00 per 1M tokens) instead of $0.

Root cause: `model_cost()` strips the provider prefix via `rsplit_once('/')`,
leaving identifiers like `step-3.5-flash:free` or `free` that don't match any
known model or the `is_local_model()` heuristic.

Fix: add an early return before prefix stripping that checks for the `:free`
suffix and the bare `free` / `openrouter/free` identifiers, returning zero cost.

Tests: 4 new test cases covering the `:free` suffix with various providers,
the `openrouter/free` router, and the bare `free` edge case.
@github-actions github-actions Bot added scope: llm LLM integration size: S 10-49 changed lines risk: low Changes to docs, tests, or low-risk modules labels Mar 6, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 resolves an issue where OpenRouter free-tier models were incorrectly reporting non-zero costs in the UI. By introducing an early cost calculation check for specific free model identifiers, the system now accurately reflects zero cost for these models, improving the precision of cost reporting for users utilizing free-tier services.

Highlights

  • Corrected cost reporting for OpenRouter free-tier models: Implemented an early return in the model_cost function to ensure that models identified by :free suffix, openrouter/free, or free report zero cost, addressing issue OpenRouter free-tier models report incorrect costs #463.
  • Enhanced model cost normalization logic: The zero-cost check is performed before provider prefix stripping to correctly identify free models, as the :free suffix is crucial for OpenRouter's routing convention.
  • Added comprehensive unit tests: Four new test cases were introduced to validate the zero-cost reporting for various free model identifiers, including suffix-based, specific router, bare free, and multiple provider-prefixed free models.
Changelog
  • src/llm/costs.rs
    • Added an early return condition in model_cost to set costs to zero for OpenRouter free-tier models.
    • Introduced four new unit tests to verify the correct zero-cost reporting for various free model patterns.
Activity
  • No activity has been recorded for this pull request yet.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@github-actions github-actions Bot added the contributor: new First-time contributor label Mar 6, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request addresses an issue where OpenRouter free-tier models were incorrectly assigned a cost. The change adds a check at the beginning of the model_cost function to identify free models by their ID and return a zero cost. This check handles models with a :free suffix, as well as the openrouter/free and free identifiers. The change is accompanied by a comprehensive set of unit tests that validate the new logic for various scenarios. The implementation is correct and aligns with the pull request's goal. No issues were found during the review.

@ilblackdragon
ilblackdragon enabled auto-merge (squash) March 7, 2026 06:57
@ilblackdragon
ilblackdragon merged commit 3f22f43 into nearai:main Mar 7, 2026
16 checks passed
@github-actions github-actions Bot mentioned this pull request Mar 7, 2026
@github-actions github-actions Bot mentioned this pull request Mar 10, 2026
bkutasi pushed a commit to bkutasi/ironclaw that referenced this pull request Mar 28, 2026
… (nearai#613)

OpenRouter models with the `:free` suffix (e.g. `stepfun/step-3.5-flash:free`)
and the `openrouter/free` router were falling through to `default_cost()`,
which reports GPT-4o pricing (~$2.50/$10.00 per 1M tokens) instead of $0.

Root cause: `model_cost()` strips the provider prefix via `rsplit_once('/')`,
leaving identifiers like `step-3.5-flash:free` or `free` that don't match any
known model or the `is_local_model()` heuristic.

Fix: add an early return before prefix stripping that checks for the `:free`
suffix and the bare `free` / `openrouter/free` identifiers, returning zero cost.

Tests: 4 new test cases covering the `:free` suffix with various providers,
the `openrouter/free` router, and the bare `free` edge case.
drchirag1991 pushed a commit to drchirag1991/ironclaw that referenced this pull request Apr 8, 2026
… (nearai#613)

OpenRouter models with the `:free` suffix (e.g. `stepfun/step-3.5-flash:free`)
and the `openrouter/free` router were falling through to `default_cost()`,
which reports GPT-4o pricing (~$2.50/$10.00 per 1M tokens) instead of $0.

Root cause: `model_cost()` strips the provider prefix via `rsplit_once('/')`,
leaving identifiers like `step-3.5-flash:free` or `free` that don't match any
known model or the `is_local_model()` heuristic.

Fix: add an early return before prefix stripping that checks for the `:free`
suffix and the bare `free` / `openrouter/free` identifiers, returning zero cost.

Tests: 4 new test cases covering the `:free` suffix with various providers,
the `openrouter/free` router, and the bare `free` edge case.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: new First-time contributor risk: low Changes to docs, tests, or low-risk modules scope: llm LLM integration size: S 10-49 changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenRouter free-tier models report incorrect costs

2 participants