mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-08-26 00:44:41 +00:00
fix(models): price Codex auto-review as GPT-5.5 and take daily v22
Maintainer review on #1056: pin the activity id to the recommended review model (existing bundled row, not an invented rate), resolve the same alias for credits, and take daily-cache 22 so this PR does not collide with #946 claiming v21.
This commit is contained in:
parent
4d15b05d84
commit
61e76b7989
7 changed files with 49 additions and 25 deletions
|
|
@ -33,7 +33,7 @@ const WORK = process.env['UPGRADE_PATH_WORK'] || join(tmpdir(), 'codeburn upgrad
|
|||
const OLD_SESSION_CACHE = 'session-cache.v7.json'
|
||||
const OLD_DAILY_CACHE = 'daily-cache.v17.json'
|
||||
const NEW_SESSION_CACHE_DIR = 'session-cache.v9'
|
||||
const NEW_DAILY_CACHE = 'daily-cache.v21.json'
|
||||
const NEW_DAILY_CACHE = 'daily-cache.v22.json'
|
||||
|
||||
const HOME = join(WORK, 'user home')
|
||||
const PAYLOADS = join(WORK, 'payloads')
|
||||
|
|
|
|||
|
|
@ -20,10 +20,19 @@ const CREDITS_PER_MILLION: Record<string, CodexCreditRate> = {
|
|||
'gpt-5.4-mini': { input: 18.75, cachedInput: 1.875, output: 113 },
|
||||
}
|
||||
|
||||
// Activity surfaces keep their product id on the call (display stays
|
||||
// "Codex Auto Review"). Credits must follow the same underlying model
|
||||
// BUILTIN_ALIASES uses for USD. Keep this table in lockstep with
|
||||
// `codex-auto-review` in src/models.ts.
|
||||
const ACTIVITY_CREDIT_MODELS: Record<string, string> = {
|
||||
'codex-auto-review': 'gpt-5.5',
|
||||
}
|
||||
|
||||
/// Resolve the credit rate for a Codex model name, tolerating suffix variants
|
||||
/// (e.g. "gpt-5.5-codex"). Returns null when the model has no known credit rate.
|
||||
export function codexCreditRate(model: string): CodexCreditRate | null {
|
||||
const m = model.toLowerCase()
|
||||
const mapped = ACTIVITY_CREDIT_MODELS[model] ?? ACTIVITY_CREDIT_MODELS[model.toLowerCase()]
|
||||
const m = (mapped ?? model).toLowerCase()
|
||||
if (m.includes('5.4') && m.includes('mini')) return CREDITS_PER_MILLION['gpt-5.4-mini']!
|
||||
if (m.includes('5.4')) return CREDITS_PER_MILLION['gpt-5.4']!
|
||||
if (m.includes('5.5')) return CREDITS_PER_MILLION['gpt-5.5']!
|
||||
|
|
|
|||
|
|
@ -6,13 +6,17 @@ import { join } from 'path'
|
|||
import { getCodeburnCacheDir } from './cache-dir.js'
|
||||
import type { DateRange, ProjectSummary } from './types.js'
|
||||
|
||||
// Bumped to 21: `codex-auto-review` now prices as the official GPT-5.4 row
|
||||
// (#1047). Days already finalized under v20 keep that id at $0 forever unless
|
||||
// MIN_SUPPORTED_VERSION moves: the daily cache has no per-provider
|
||||
// invalidation. The Codex parse version and CODEX_CACHE_VERSION move with
|
||||
// this so the lower caches reprice first; this pass then re-derives ALL days
|
||||
// from the warm session cache (seconds, not a full re-parse). adoptOlderDailyCaches
|
||||
// keeps the superseded v20 file as the baseline.
|
||||
// Bumped to 22: `codex-auto-review` now prices as the recommended GPT-5.5
|
||||
// row (#1047). Days already finalized under v20/v21 keep that id at $0
|
||||
// forever unless MIN_SUPPORTED_VERSION moves: the daily cache has no
|
||||
// per-provider invalidation. The Codex parse version and CODEX_CACHE_VERSION
|
||||
// move with this so the lower caches reprice first; this pass then re-derives
|
||||
// ALL days from the warm session cache (seconds, not a full re-parse).
|
||||
// adoptOlderDailyCaches keeps the superseded file as the baseline. v22 not
|
||||
// v21: #946 (in landing) already claims 21.
|
||||
//
|
||||
// Bumped to 21: unreleased on this branch; skipped so we do not collide
|
||||
// with #946's daily-cache.v21.json.
|
||||
//
|
||||
// Bumped to 20: the Codex fast-path read a nested
|
||||
// `base_instructions.provenance.model` out of `session_meta` as if it were
|
||||
|
|
@ -118,8 +122,8 @@ import type { DateRange, ProjectSummary } from './types.js'
|
|||
// that older binaries skipped. v8 added local-model savings to the daily
|
||||
// rollup; the `savingsConfigHash` field is invalidated separately when the
|
||||
// user changes their `localModelSavings` mapping.
|
||||
export const DAILY_CACHE_VERSION = 21
|
||||
const MIN_SUPPORTED_VERSION = 21
|
||||
export const DAILY_CACHE_VERSION = 22
|
||||
const MIN_SUPPORTED_VERSION = 22
|
||||
// Version-suffixed so different binaries each own a distinct file and never
|
||||
// clobber an incompatible schema. Bumping the version mints a fresh filename;
|
||||
// adoptOlderDailyCaches then unions days out of every previous file (including
|
||||
|
|
|
|||
|
|
@ -283,14 +283,15 @@ const BUILTIN_ALIASES: Record<string, string> = {
|
|||
'warp-auto-efficient': 'gpt-5.3-codex',
|
||||
'warp-auto-powerful': 'claude-opus-4-6',
|
||||
// Codex activity ids are product surfaces, not subscription SKUs and not
|
||||
// LiteLLM rows. Official rate card (help.openai.com/articles/20001106,
|
||||
// 2026-08-20): "Auto review uses GPT-5.4." Price as that existing row.
|
||||
// Do not invent a rate. Do not treat the id as honestly $0 — it consumes
|
||||
// the same credit pool as other Codex work. Display stays on
|
||||
// autoModelNames (same class as cursor-auto / copilot-openai-auto).
|
||||
// LiteLLM rows. OpenAI's tracker (openai/codex#32224) says auto review
|
||||
// consumes normal model usage. Public evidence: review_model defaults to
|
||||
// the session model; GPT-5.5 is the currently recommended review model.
|
||||
// Price as that existing bundled row. Do not invent a rate. Do not treat
|
||||
// the id as honestly $0 — it draws from the same credit pool. Display
|
||||
// stays on autoModelNames (same class as cursor-auto / copilot-openai-auto).
|
||||
// Only alias ids observed in Codex source / real rollouts. Do not infer
|
||||
// `codex-code-review` from the activity name "code review".
|
||||
'codex-auto-review': 'gpt-5.4',
|
||||
'codex-auto-review': 'gpt-5.5',
|
||||
'grok-build': 'grok-build-0.1',
|
||||
'GPT-5.3 Codex (low reasoning)': 'gpt-5.3-codex',
|
||||
'GPT-5.3 Codex (medium reasoning)': 'gpt-5.3-codex',
|
||||
|
|
|
|||
|
|
@ -17,6 +17,12 @@ describe('codexCreditRate', () => {
|
|||
expect(codexCreditRate('gpt-4o')).toBeNull()
|
||||
expect(codexCreditRate('claude-opus-4-8')).toBeNull()
|
||||
})
|
||||
|
||||
it('resolves the auto-review activity id to the same rate as GPT-5.5', () => {
|
||||
expect(codexCreditRate('codex-auto-review')).toEqual(codexCreditRate('gpt-5.5'))
|
||||
expect(codexCreditRate('codex-auto-review')).not.toBeNull()
|
||||
expect(codexCreditRate('CODEX-AUTO-REVIEW')).toEqual(codexCreditRate('gpt-5.5'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('codexCredits', () => {
|
||||
|
|
@ -50,4 +56,8 @@ describe('codexCredits', () => {
|
|||
it('returns null for an unknown model', () => {
|
||||
expect(codexCredits('gpt-4o', { inputTokens: 1_000_000, cachedReadTokens: 0, outputTokens: 0 })).toBeNull()
|
||||
})
|
||||
|
||||
it('charges auto-review at the GPT-5.5 credit rate, not null', () => {
|
||||
expect(codexCredits('codex-auto-review', { inputTokens: 1_000_000, cachedReadTokens: 0, outputTokens: 0 })).toBe(125)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -610,7 +610,7 @@ describe('Cursor model variants resolve to pricing', () => {
|
|||
// Cursor auto proxy
|
||||
['cursor-auto', 'claude-sonnet-4-5'],
|
||||
// Codex activity surface (official rate card, observed raw id)
|
||||
['codex-auto-review', 'gpt-5.4'],
|
||||
['codex-auto-review', 'gpt-5.5'],
|
||||
// OpenAI variants Cursor emits
|
||||
['gpt-5', 'gpt-5'],
|
||||
['gpt-5-fast', 'gpt-5'],
|
||||
|
|
@ -651,12 +651,12 @@ describe('Codex activity ids (#1047)', () => {
|
|||
expect(getShortModelName('codex-auto-review')).toBe('Codex Auto Review')
|
||||
})
|
||||
|
||||
it('prices as the exact bundled GPT-5.4 object, not an invented rate', () => {
|
||||
expect(getModelCosts('codex-auto-review')).toBe(getModelCosts('gpt-5.4'))
|
||||
it('prices as the exact bundled GPT-5.5 object, not an invented rate', () => {
|
||||
expect(getModelCosts('codex-auto-review')).toBe(getModelCosts('gpt-5.5'))
|
||||
const auto = calculateCost('codex-auto-review', 1_000_000, 1_000_000, 0, 0, 0)
|
||||
const gpt54 = calculateCost('gpt-5.4', 1_000_000, 1_000_000, 0, 0, 0)
|
||||
const gpt55 = calculateCost('gpt-5.5', 1_000_000, 1_000_000, 0, 0, 0)
|
||||
expect(auto).toBeGreaterThan(0)
|
||||
expect(auto).toBe(gpt54)
|
||||
expect(auto).toBe(gpt55)
|
||||
})
|
||||
|
||||
it('does not invent a family or an unobserved sibling id', () => {
|
||||
|
|
|
|||
|
|
@ -1201,7 +1201,7 @@ describe('codex provider - forked session dedupe', () => {
|
|||
})
|
||||
|
||||
describe('codex auto-review pricing (#1047)', () => {
|
||||
it('parses auto-review as itself and prices it as GPT-5.4', async () => {
|
||||
it('parses auto-review as itself and prices it as GPT-5.5', async () => {
|
||||
const filePath = await writeSession(tmpDir, '2026-04-14', 'rollout-auto-review.jsonl', [
|
||||
sessionMeta({ session_id: 'sess-auto', model: 'codex-auto-review' }),
|
||||
userMessage('review the PR'),
|
||||
|
|
@ -1218,7 +1218,7 @@ describe('codex auto-review pricing (#1047)', () => {
|
|||
}
|
||||
expect(calls).toHaveLength(1)
|
||||
expect(calls[0]!.model).toBe('codex-auto-review')
|
||||
expect(calls[0]!.costUSD).toBe(calculateCost('gpt-5.4', 1_000_000, 1_000_000, 0, 0, 0))
|
||||
expect(calls[0]!.costUSD).toBe(calculateCost('gpt-5.5', 1_000_000, 1_000_000, 0, 0, 0))
|
||||
})
|
||||
|
||||
it('discards a warm v9 $0 exact hit so unchanged rollouts reprice', async () => {
|
||||
|
|
@ -1262,7 +1262,7 @@ describe('codex auto-review pricing (#1047)', () => {
|
|||
}
|
||||
expect(calls).toHaveLength(1)
|
||||
expect(calls[0]!.costUSD).toBeGreaterThan(0)
|
||||
expect(calls[0]!.costUSD).toBe(calculateCost('gpt-5.4', 1_000_000, 1_000_000, 0, 0, 0))
|
||||
expect(calls[0]!.costUSD).toBe(calculateCost('gpt-5.5', 1_000_000, 1_000_000, 0, 0, 0))
|
||||
} finally {
|
||||
clearCodexMemCaches()
|
||||
if (prev === undefined) delete process.env['CODEBURN_CACHE_DIR']
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue