diff --git a/src/daily-cache.ts b/src/daily-cache.ts index 6c486791..64843457 100644 --- a/src/daily-cache.ts +++ b/src/daily-cache.ts @@ -5,14 +5,18 @@ import { homedir } from 'os' import { join } from 'path' import type { DateRange, ProjectSummary } from './types.js' -// Bumped to 8: local-model savings accounting is now part of the daily rollup -// (savingsUSD per day / per model / per category / per provider). Stale entries -// computed by older binaries lack those fields, so MIN_SUPPORTED_VERSION is -// also raised to 8 to force a full re-hydration. The `savingsConfigHash` field -// is invalidated separately when the user changes their `localModelSavings` -// mapping so historical "saved" totals stay in sync with the active baseline. -export const DAILY_CACHE_VERSION = 8 -const MIN_SUPPORTED_VERSION = 8 +// Bumped to 9: providers added since the v8 rollup (Grok, Hermes, ZCode) parse +// usage that older binaries skipped, so days cached at v8 omit them and report +// $0 for those providers across history. Raising MIN_SUPPORTED_VERSION to 9 too +// forces a one-time full re-hydration so newly supported providers backfill +// without a manual cache clear. +// +// v8 added local-model savings to the daily rollup (savingsUSD per day / model / +// category / provider). The `savingsConfigHash` field is invalidated separately +// when the user changes their `localModelSavings` mapping so historical "saved" +// totals stay in sync with the active baseline. +export const DAILY_CACHE_VERSION = 9 +const MIN_SUPPORTED_VERSION = 9 const DAILY_CACHE_FILENAME = 'daily-cache.json' export type DailyEntry = { diff --git a/src/models.ts b/src/models.ts index 52ec0026..4d04c1ad 100644 --- a/src/models.ts +++ b/src/models.ts @@ -663,6 +663,14 @@ const SHORT_NAMES: Record = { 'o3': 'o3', 'MiniMax-M2.7-highspeed': 'MiniMax M2.7 Highspeed', 'MiniMax-M2.7': 'MiniMax M2.7', + // Grok (xAI) and GLM ids that otherwise surface raw or as a pricing key in + // reports. grok-build and GLM-5.2 price via sibling aliases, so + // getShortModelName resolves to the pricing key before this lookup; map each + // back to the real model name. grok-composer has no alias, it just lacked an + // entry. + 'glm-5p1': 'GLM-5.2', // ZCode/Hermes run GLM-5.2 (priced as the GLM-5.1 sibling) + 'grok-build-0.1': 'Grok Build', // Grok Build prices through the 0.1 sibling + 'grok-composer-2.5-fast': 'Grok Composer 2.5 Fast', } // Sorted longest-first so more-specific prefixes match before shorter ones. diff --git a/tests/models.test.ts b/tests/models.test.ts index 2bdf8feb..403a5550 100644 --- a/tests/models.test.ts +++ b/tests/models.test.ts @@ -88,6 +88,19 @@ describe('getShortModelName', () => { expect(getShortModelName('claude-haiku-5')).toBe('Haiku 5') expect(getShortModelName('claude-opus-9-9-20300101')).toBe('Opus 9.9') }) + + it('shows the real model name for pricing-sibling aliases, not the internal key', () => { + // GLM-5.2 (and its lowercase Hermes spelling) price via the glm-5p1 sibling; + // reports must show GLM-5.2, not the pricing key. + expect(getShortModelName('GLM-5.2')).toBe('GLM-5.2') + expect(getShortModelName('glm-5.2')).toBe('GLM-5.2') + expect(getShortModelName('glm-5p1')).toBe('GLM-5.2') + // Grok Build prices via the grok-build-0.1 sibling. + expect(getShortModelName('grok-build')).toBe('Grok Build') + expect(getShortModelName('grok-build-0.1')).toBe('Grok Build') + // grok-composer has no alias, just a missing display entry. + expect(getShortModelName('grok-composer-2.5-fast')).toBe('Grok Composer 2.5 Fast') + }) }) describe('claude-fable-5 pricing + name', () => {