Skip to content

feat: enhance cost formatting and add Codex GPT-5.5 pricing support - #1944

Merged
diegosouzapw merged 1 commit into
diegosouzapw:release/v3.7.9from
JxnLexn:main
May 4, 2026
Merged

diegosouzapw merged 1 commit into
diegosouzapw:release/v3.7.9from
JxnLexn:main

Conversation

@JxnLexn

@JxnLexn JxnLexn commented May 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fixes Costs/Analytics cost statistics for Codex GPT-5.5 combo usage so estimated costs no longer show as $0.00 when token usage exists and pricing is configured.
  • Improves Codex pricing resolution for provider aliases, GPT-5.5 effort variants, and codex-auto-review.
  • Prevents normal combo routing from being counted as a fallback in Costs/Analytics fallback statistics.
  • Updates the Costs page to display sub-cent cost values with enough precision instead of rounding them to $0.00.

Related Issues

Validation

  • npm run lint
    • Passed with 0 errors, 1994 warnings.
  • npm run test:unit
    • Failed due to an existing unrelated failing test:
      • plan3-p0.test.ts
      • getModelInfoCore resolves unique non-openai unprefixed model
      • Assertion: null !== 'claude'
    • Targeted changed test passed separately: usage-analytics-route.test.ts (14/14).
  • npm run test:coverage
    • Failed because the same unrelated unit test failed.
  • Coverage is still >= 60% for statements, lines, functions, and branches
    • Statements: 83.43%
    • Lines: 83.43%
    • Functions: 86.53%
    • Branches: 75.2%
  • SonarQube PR analysis is green or any remaining issues are explicitly documented below
    • Not run locally: no active PR was available and sonar-scanner was not installed.
    • Remaining known issue: the unrelated plan3-p0.test.ts failure above prevents a fully green local unit/coverage gate.

Tests Added Or Updated

  • Updated usage-analytics-route.test.ts
    • Added Codex GPT-5.5 provider-alias pricing coverage.
    • Added codex-auto-review → GPT-5.5 pricing coverage.
    • Added combo-routing fallback-statistics coverage.

Coverage Notes

  • This PR changes production code in src.
  • Coverage for the change is provided by usage-analytics-route.test.ts, which validates:
    • estimated cost calculation for codex/gpt-5.5,
    • estimated cost calculation for codex-auto-review,
    • combo route executions are not counted as fallback events.
  • The touched test file passed locally (14/14).
  • Full coverage remained above the required 60% threshold for all metrics, but the coverage command exited non-zero due to the unrelated plan3-p0 test failure.

Reviewer Notes

  • No database migrations or feature flags were added.
  • The fallback-rate change intentionally excludes rows with combo_name from fallback counting, because combo model selection is normal routing, not a fallback.
  • Cost formatting only affects the Costs page KPI display for sub-cent values; exported raw costs and analytics calculations remain numeric.

Copilot AI review requested due to automatic review settings May 4, 2026 11:59
@JxnLexn
JxnLexn requested a review from diegosouzapw as a code owner May 4, 2026 11:59

@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 introduces dynamic currency formatting in the cost dashboard to support higher precision for small values and refactors the analytics API's model pricing resolution to handle various model name formats and suffixes more robustly. Additionally, the SQL logic for calculating fallback statistics was refined to exclude combo-routed requests and ensure case-insensitive comparisons. Feedback was provided regarding the performance of the new currency formatting function, suggesting that Intl.NumberFormat instances should be cached to avoid unnecessary overhead during component re-renders.

Comment on lines +114 to +133
function formatCurrencyCost(locale: string, value: number): string {
const numericValue = Number(value || 0);
if (!Number.isFinite(numericValue) || numericValue === 0) {
return new Intl.NumberFormat(locale, {
style: "currency",
currency: "USD",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(0);
}

const absValue = Math.abs(numericValue);
const fractionDigits = absValue < 0.01 ? 6 : absValue < 1 ? 4 : 2;
return new Intl.NumberFormat(locale, {
style: "currency",
currency: "USD",
minimumFractionDigits: fractionDigits,
maximumFractionDigits: fractionDigits,
}).format(numericValue);
}

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.

medium

Creating a new Intl.NumberFormat instance on every call to formatCurrencyCost is inefficient, as this function is executed multiple times during component rendering and Intl.NumberFormat instantiation is computationally expensive. Consider caching the formatters for the different precision levels (2, 4, and 6 digits) to improve performance.

const currencyFormatters = new Map<string, Intl.NumberFormat>();

function getCurrencyFormatter(locale: string, digits: number) {
  const key = locale + "-" + digits;
  let formatter = currencyFormatters.get(key);
  if (!formatter) {
    formatter = new Intl.NumberFormat(locale, {
      style: "currency",
      currency: "USD",
      minimumFractionDigits: digits,
      maximumFractionDigits: digits,
    });
    currencyFormatters.set(key, formatter);
  }
  return formatter;
}

function formatCurrencyCost(locale: string, value: number): string {
  const numericValue = Number(value || 0);
  if (!Number.isFinite(numericValue) || numericValue === 0) {
    return getCurrencyFormatter(locale, 2).format(0);
  }

  const absValue = Math.abs(numericValue);
  const fractionDigits = absValue < 0.01 ? 6 : absValue < 1 ? 4 : 2;
  return getCurrencyFormatter(locale, fractionDigits).format(numericValue);
}

Copilot AI 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.

Pull request overview

This PR fixes cost estimation and fallback-rate reporting for Codex GPT-5.5 (including provider alias resolution and codex-auto-review), and improves the Costs dashboard display so sub-cent spend isn’t rounded down to $0.00.

Changes:

  • Extend pricing resolution in usage analytics to handle provider aliases, Codex GPT-5.5 effort variants, and codex-auto-review mapping.
  • Adjust fallback statistics to exclude normal combo routing and make model comparisons case-insensitive.
  • Update Costs dashboard KPI formatting to show more precision for small currency values; add unit tests covering the new analytics behaviors.

Validation / Coverage (from PR description):

  • Commands run by author: npm run lint (pass); targeted usage-analytics-route.test.ts (pass).
  • npm run test:coverage currently exits non-zero due to an unrelated failing unit test (plan3-p0.test.ts), though reported coverage remains ≥ 60% (Statements/Lines 83.43%, Functions 86.53%, Branches 75.2%).
  • Commands run in this review environment: not run.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
tests/unit/usage-analytics-route.test.ts Adds unit coverage for Codex GPT-5.5 alias pricing, codex-auto-review pricing mapping, and combo routing exclusion from fallback stats.
src/shared/constants/pricing.ts Adds default pricing entry for codex-auto-review under Codex (cx) defaults.
src/app/api/usage/analytics/route.ts Improves pricing lookup candidate resolution and refines fallback eligibility/rate calculations to exclude combo routing.
src/app/(dashboard)/dashboard/costs/CostOverviewTab.tsx Improves displayed currency precision for sub-cent KPI values on the Costs overview.

Comment on lines +117 to +123
return new Intl.NumberFormat(locale, {
style: "currency",
currency: "USD",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(0);
}
Comment on lines +127 to +132
return new Intl.NumberFormat(locale, {
style: "currency",
currency: "USD",
minimumFractionDigits: fractionDigits,
maximumFractionDigits: fractionDigits,
}).format(numericValue);
@diegosouzapw
diegosouzapw changed the base branch from main to release/v3.7.9 May 4, 2026 12:26
@JxnLexn

JxnLexn commented May 4, 2026

Copy link
Copy Markdown
Contributor Author

@copilot apply changes based on the comments in this thread

@diegosouzapw
diegosouzapw merged commit 9577a8d into diegosouzapw:release/v3.7.9 May 4, 2026
1 of 2 checks passed
@diegosouzapw

Copy link
Copy Markdown
Owner

Thanks @JxnLexn for this great contribution! 🎉 I resolved some branch conflicts by rebasing it onto our latest release/v3.7.9 branch. It's now officially merged! We appreciate your effort!

This was referenced May 5, 2026
diegosouzapw added a commit that referenced this pull request Jun 20, 2026
diegosouzapw added a commit that referenced this pull request Jun 20, 2026
diegosouzapw added a commit that referenced this pull request Jun 21, 2026
… envelope (port from 9router#1926) (#4485)

The unified thinking adapter can set Claude/OpenAI-native thinking fields
(thinking, reasoning_effort, reasoning, enable_thinking, thinking_budget) at
the request body root. The Antigravity envelope spreads ...passthroughFields,
so these leaked into the Google Cloud Code envelope and Google rejected the
request with `400 Bad input: oneOf at '/' not met` (or `Unknown name
"thinking"`), breaking every reasoning/thinking model served via Antigravity
(e.g. claude-opus-4-x-thinking).

Extends the existing #1944 envelope strip (output_config/output_format) to
also drop the whole thinking family. Gemini's own generationConfig.thinkingConfig
travels inside the inner request and is unaffected, so thinking still works.

Reported-by: theseven99 (decolua/9router#1926)

Co-authored-by: Arcfoz <62255009+Arcfoz@users.noreply.github.com>
diegosouzapw added a commit to Witroch4/OmniRoute that referenced this pull request Jun 21, 2026
… envelope (port from 9router#1926) (diegosouzapw#4485)

The unified thinking adapter can set Claude/OpenAI-native thinking fields
(thinking, reasoning_effort, reasoning, enable_thinking, thinking_budget) at
the request body root. The Antigravity envelope spreads ...passthroughFields,
so these leaked into the Google Cloud Code envelope and Google rejected the
request with `400 Bad input: oneOf at '/' not met` (or `Unknown name
"thinking"`), breaking every reasoning/thinking model served via Antigravity
(e.g. claude-opus-4-x-thinking).

Extends the existing diegosouzapw#1944 envelope strip (output_config/output_format) to
also drop the whole thinking family. Gemini's own generationConfig.thinkingConfig
travels inside the inner request and is unaffected, so thinking still works.

Reported-by: theseven99 (decolua/9router#1926)

Co-authored-by: Arcfoz <62255009+Arcfoz@users.noreply.github.com>
(cherry picked from commit 5a7c1e1)
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
Poid-ZA pushed a commit to Poid-ZA/OmniRoute that referenced this pull request Aug 5, 2026
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
… envelope (port from 9router#1926) (diegosouzapw#4485)

The unified thinking adapter can set Claude/OpenAI-native thinking fields
(thinking, reasoning_effort, reasoning, enable_thinking, thinking_budget) at
the request body root. The Antigravity envelope spreads ...passthroughFields,
so these leaked into the Google Cloud Code envelope and Google rejected the
request with `400 Bad input: oneOf at '/' not met` (or `Unknown name
"thinking"`), breaking every reasoning/thinking model served via Antigravity
(e.g. claude-opus-4-x-thinking).

Extends the existing diegosouzapw#1944 envelope strip (output_config/output_format) to
also drop the whole thinking family. Gemini's own generationConfig.thinkingConfig
travels inside the inner request and is unaffected, so thinking still works.

Reported-by: theseven99 (decolua/9router#1926)

Co-authored-by: Arcfoz <62255009+Arcfoz@users.noreply.github.com>
(cherry picked from commit 10412d0)
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
… envelope (port from 9router#1926) (diegosouzapw#4485)

The unified thinking adapter can set Claude/OpenAI-native thinking fields
(thinking, reasoning_effort, reasoning, enable_thinking, thinking_budget) at
the request body root. The Antigravity envelope spreads ...passthroughFields,
so these leaked into the Google Cloud Code envelope and Google rejected the
request with `400 Bad input: oneOf at '/' not met` (or `Unknown name
"thinking"`), breaking every reasoning/thinking model served via Antigravity
(e.g. claude-opus-4-x-thinking).

Extends the existing diegosouzapw#1944 envelope strip (output_config/output_format) to
also drop the whole thinking family. Gemini's own generationConfig.thinkingConfig
travels inside the inner request and is unaffected, so thinking still works.

Reported-by: theseven99 (decolua/9router#1926)

Co-authored-by: Arcfoz <62255009+Arcfoz@users.noreply.github.com>
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
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.

[BUG] Est. Cost $0.00

3 participants