Skip to content

feat(usage): price GPT-6 Astra token usage - #22006

Closed
Alfred212121 wants to merge 1 commit into
stablyai:mainfrom
Alfred212121:fix/price-gpt-6-astra-codex-usage
Closed

Alfred212121 wants to merge 1 commit into
stablyai:mainfrom
Alfred212121:fix/price-gpt-6-astra-codex-usage

Conversation

@Alfred212121

@Alfred212121 Alfred212121 commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

ELI5

Orca's Stats & Usage page works out what your Codex sessions cost by looking each model up in a price list. GPT-6 Astra was never added to that list, so Orca quietly counted it as free. On my own data that hid roughly $2,200 of Codex usage behind a near-zero number. This adds Astra to the list.

What Changed

Before: any Codex session run on gpt-6-astra contributed $0 to the estimated cost in Settings → Stats & Usage — on the Usage Overview tile, the Codex provider card, and the per-model and per-project breakdowns. There was no "inferred pricing" note either, so the figure looked authoritative while being off by orders of magnitude.

After: those sessions are priced at the published Astra rates and the totals reflect real spend.

Mechanism: MODEL_PRICING in src/main/codex-usage/codex-model-pricing.ts stopped at gpt-5.6-luna, and normalizeModelForPricing() had no branch for Astra, so it fell through to return null. estimateCostUsd() returns null on a null normalization, and the aggregation treats that as "no cost" rather than "unknown cost". The hasInferredPricing flag doesn't catch this: it is set when the rollout has no model name at all, not when a named model is missing from the table.

Two additions:

  • a gpt-6-astra entry at $10 input / $1 cached input / $50 output per 1M, with inputTiers / cachedInputTiers / outputTiers at $20 / $2 / $75 above LONG_CONTEXT_THRESHOLD_TOKENS;
  • a normalizer branch matching gpt-6-astra and gpt-6-astra-*, placed before the bare gpt-5.6 alias check so it can't be shadowed, and after the 5.6 tier IDs so it doesn't shadow them.

Why

The rates are what OpenAI publishes for the model (docs): $10 / $1 / $50 per 1M, and "prompts with more than 272K input tokens are priced at 2x input and cache rates and 1.5x output for the full request". That long-context rule is exactly what the existing TieredPrice fields already express, and 272K is already LONG_CONTEXT_THRESHOLD_TOKENS, so no new machinery is needed — this follows the same shape as #10822, which added the GPT-5.6 family.

The alternative would be to make an unpriced-but-named model surface as hasInferredPricing so the UI says "inferred pricing" instead of showing a wrong number. That's arguably worth doing as a general safety net for the next model launch, but it's a separate behavioral change and doesn't help anyone running Astra today. I kept this PR to the data gap.

One thing I deliberately left out: codex-auto-review also appears as its own model key in rollouts (200M tokens and ~$434 of unpriced usage in my data) and is likewise absent from the table. I don't know what it actually bills as, so I didn't guess. Happy to add it in a follow-up if a maintainer can confirm.

Linked Issue

Fixes #22005

Visual Proof

No layout or interaction change — the same cost strings render, with correct numbers.

Before/after on my own orca-codex-usage.json, both sides computed over the identical set of daily aggregate rows so the comparison is like-for-like:

Codex est. cost
before $2.04
after $2,207.51

The gpt-6-astra token totals behind that: 24,838,404 uncached input + 802,453,760 cached input + 2,895,411 output.

Two notes on the numbers, since an earlier revision of this description got them wrong:

  • The figure is not the flat base rates applied to the totals (that would be $1,195.61). buildSummary() calls estimateCostUsd() once per day::model::projectKey row, so the 272K tiers fire on most rows and the real total is ~84% higher. Thanks to the review bot for catching that.
  • I originally quoted $0.47 as the "before". That is what the provider card renders under its own default scope/range filter, not the all-rows total, so pairing it with an all-rows "after" was apples-to-oranges. Both numbers above are all-rows.

No screenshots: the surrounding panel lists my private project and worktree names.

Testing

Added two cases to src/main/codex-usage/store-model-pricing.test.ts, following the existing GPT-5.6 ones:

  • prices GPT-6 Astra with current OpenAI rates — 2M input / 1M cached / 1M output crosses the 272K threshold and must come to $87.208;
  • normalizes GPT-6 Astra reasoning suffixes and snapshot IDs before pricing — gpt-6-astra-high and gpt-6-astra-2026-09-01 both price as gpt-6-astra at $1.80 under the threshold.

I verified those two expected values, plus that the existing gpt-5.6-sol / gpt-5.6-terra-high / bare gpt-5.6 / gpt-5.6-luna expectations are unchanged and that an unknown model still returns null, by executing estimateCostUsd() directly against this diff. I was not able to run the full pnpm test / pnpm tc / pnpm build locally — pulling and installing the whole workspace is impractical on my connection — so I'm relying on CI for those. The change is confined to one pure data table and one pure string function, with no platform-, SSH-, or mobile-specific behavior.

  • I manually tested these changes locally
  • Automated tests added/updated, or explained why not below

Manual verification was done against the real orca-codex-usage.json numbers above rather than in a locally built app, for the same build reason.

AI Disclosure

Written with Claude Opus 5 (Claude Code). The pricing figures were taken from OpenAI's published model docs and the arithmetic in the new tests was checked against the existing GPT-5.6 cases.

Review

Agent skill upstream boundary

  • Not applicable, or this change follows docs/reference/agent-skill-sharing-upstream-boundary.md and copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

No security, cross-platform, remote-SSH, mobile, or performance impact: one static object literal gains a key and one pure function gains an equality/prefix check. Backwards compatible — previously unpriced sessions start showing a cost, and no existing model's rate changes.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

Understand this PR’s impact

Explore downstream dependencies and potential security impact with Blast Radius.

View blast radius →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: fbaa525a-e1a6-478d-8348-ddb157edabd3

📥 Commits

Reviewing files that changed from the base of the PR and between 4aaa6c7 and e535ec10be4f2fbb7d1169cb119dea86429c1d26.

📒 Files selected for processing (2)
  • src/main/codex-usage/codex-model-pricing.ts
  • src/main/codex-usage/store-model-pricing.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The pricing table now includes GPT-6 Astra rates and long-context tiers. Model normalization maps gpt-6-astra and names with the gpt-6-astra- prefix to that pricing entry. Tests verify estimated costs for standard, reasoning-suffix, and snapshot model names.

Priority: ➖ Normal

Severity of issue fixed: Medium

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Issue #22005 requires pricing for gpt-6-astra and normalization of its model variants. The PR adds gpt-6-astra to MODEL_PRICING with input $10, cached input $1, and output $50 per 1M token…
Out of Scope Changes check ✅ Passed The changed source file contains only the Astra pricing entry and normalization branch. The test changes cover Astra pricing and normalization. These changes directly support issue #22005. No unrelate…
Title check ✅ Passed The title clearly and concisely states the primary change: adding GPT-6 Astra pricing to usage calculations.
Description check ✅ Passed The description is complete and directly addresses the change, user impact, rationale, linked issue, testing, AI disclosure, compatibility considerations, and checklist. It does not use the exact `N/A…
  • Fix all pre-merge checks with AI

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.

gpt-6-astra was missing from MODEL_PRICING, so normalizeModelForPricing
returned null and estimateCostUsd dropped every event on that model from
the total. Stats & Usage showed ~$0 for hundreds of millions of tokens
with no unpriced indicator, since hasInferredPricing only covers a
missing model name, not a missing table entry.

Rates are the published ones: $10 input / $1 cached input / $50 output
per 1M, with the >272K long-context tier at 2x input and cache and 1.5x
output, which the existing tier fields already express.

Fixes stablyai#22005

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Alfred212121
Alfred212121 force-pushed the fix/price-gpt-6-astra-codex-usage branch from e535ec1 to 515aa3b Compare September 21, 2026 12:58

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes

Reviewed the full 2-file diff at e535ec1 (e535ec10be).

  • gpt-6-astra pricing entry — adds the model to MODEL_PRICING at $10 input / $1 cached / $50 output per 1M, with 2x / 2x / 1.5x long-context tiers at the existing LONG_CONTEXT_THRESHOLD_TOKENS (272K), matching the rates cited in #22005.
  • normalizeModelForPricing branch — resolves gpt-6-astra and gpt-6-astra-* so reasoning suffixes (-high) and snapshot IDs (-2026-09-01) price at Astra rates. It shadows no existing branch and is not shadowed by the bare gpt-5.6 exact match.
  • Two new tests — pin the tiered total ($87.208 for 2M / 1M / 1M) and suffix/snapshot normalization ($1.80); each fails without the new entry, so they are real coverage rather than theatre.

ℹ️ The "after" cost in the PR description looks like it omits the long-context tier

The $1,195.61 figure is exactly the published base rates applied to every token (24,838,404 × $10 + 802,453,760 × $1 + 2,895,411 × $50). But estimateCostUsd applies inputTiers / cachedInputTiers / outputTiers to each daily aggregate row (day::model::projectKey), not per request, so any row whose bucket exceeds 272K is repriced at 2x / 2x / 1.5x. With ~802M cached tokens that tier is likely to fire on most rows, which would put the card nearer $2.3K than the $1.2K shown. Worth confirming against the running app so the PR's before/after reflects what ships.

Technical details
# Long-context tiers apply per daily aggregate row, not per request

## Affected sites
- `src/main/codex-usage/codex-usage-cost-estimate.ts:4` — `calculateTieredCost` charges the base rate up to the threshold and the tier rate only above it (marginal).
- `src/main/codex-usage/codex-usage-rollup-projections.ts:49` — `buildSummary` calls `estimateCostUsd` once per `filteredDaily` row.
- `src/main/usage/usage-rollup-records.ts:105` — the row key is `day::model::projectKey`.
- `src/main/codex-usage/codex-model-pricing.ts:81` — the new Astra entry wires 272K tiers to 20 / 2 / 75.

## Required outcome
- Confirm the figure in the PR description against the actual rendered card. If the rows are large, the description should state the higher number (or explain the tier). No code change is necessarily required — the entry follows the existing convention.

## Open questions for the human
- Is aggregate-level (rather than per-request) tiering the intended model here? That is pre-existing behavior shared by every model in the table, so it is not a defect this PR introduces.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes

The head moved from e535ec1 to 515aa3b (same commit subject, force-pushed), but the diff is byte-identical to the version reviewed in my prior review — no new code or test content. No new findings; the prior review stands.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@Alfred212121

Copy link
Copy Markdown
Contributor Author

Good catch — you were right, and my "after" figure was wrong. I re-ran it against the real daily aggregate rows through buildSummary()'s actual path rather than doing the arithmetic by hand:

gpt-6-astra est. cost
flat base rates on the totals (what I wrongly wrote) $1,195.61
per day::model::projectKey row, as the app computes it $2,207.51

84.5% higher, close to your ~$2.3K estimate. With ~802M cached input tokens spread over the rows, most of them clear the 272K threshold and get repriced. I've corrected the PR description.

A second error in the same section, which you didn't flag but which follows from yours: I had quoted $0.47 as the "before". That is what the provider card renders under its own default scope/range filter, while my "after" was computed over all rows — apples-to-oranges. The like-for-like pair over the identical row set is $2.04 → $2,207.51.

No code change from either: the entry follows the same tier convention as every other model in the table, and both tests still pass.

On your open question

Is aggregate-level (rather than per-request) tiering the intended model here?

I don't think it is, and I'd like to flag it for a maintainer as a separate issue rather than fold it into this PR.

OpenAI's rule is per request — "prompts with more than 272K input tokens are priced at 2x input and cache rates and 1.5x output for the full request". A daily aggregate row is a sum over many requests, so a day of small requests that happens to total more than 272K gets billed as if it were one oversized prompt. That systematically overestimates, and it affects every tiered entry already in the table (gpt-5.4, gpt-5.4-pro, gpt-5.5, gpt-5.5-pro, the 5.6 family), not just Astra.

Fixing it properly needs per-event or per-request token counts to survive into the rollup, which is a real change to the aggregation shape — well outside a pricing-table addition. As you say, it is pre-existing behavior this PR doesn't introduce, so I've followed the existing convention here and kept the scope tight. Happy to open a separate issue for it if that's useful.

@nwparker

Copy link
Copy Markdown
Contributor

Closing as superseded by merged PR #22073, which adds GPT-6 Astra pricing and also handles unpriced model totals; linked issue #22005 is completed.

@nwparker nwparker closed this 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]: Codex usage cost is ~$0 for gpt-6-astra — model missing from the pricing table

2 participants