fix(copilot): price JetBrains claude-opus-4.7 as Opus 4.7

The dot-minor lookahead from #1531 stops claude-opus-4 matching
claude-opus-4.7, and 4.7 was not in the token list, so those turns fell
back to copilot-anthropic-auto (Sonnet 4.5 rates). Add the token and bump
the copilot session-cache parse tag so cached turns re-parse.
This commit is contained in:
Resham Joshi 2026-10-09 08:42:05 -07:00
parent 83a18e1308
commit f0421106a7
3 changed files with 11 additions and 1 deletions

View file

@ -1858,6 +1858,7 @@ function createChatSessionParser(
// specific name (e.g. "gpt-4.1-mini" before "gpt-4.1").
const JETBRAINS_MODEL_TOKENS = [
'claude-opus-4.8',
'claude-opus-4.7',
'claude-opus-4.6',
'claude-opus-4.5',
'claude-opus-4.1',

View file

@ -487,7 +487,9 @@ export const PROVIDER_PARSE_VERSIONS: Record<string, string> = {
// store-row-output-v1: every session-store row carries its own
// output_tokens; serve time zeroes it where a per-turn call owns the output.
// Keys are unchanged, so the re-parse replaces cached output-0 rows in place.
copilot: 'cli-shutdown-cost-v1-skills-source-provenance-v1-session-store-v3-chatsession-otel-skills-v1-otel-trace-metadata-once-v1-transcript-unknown-usage-v1-otel-workspace-project-v1-journal-request-input-v1-tokenless-turns-v1-store-row-output-v1',
// jetbrains-opus-4-7-v1: JetBrains claude-opus-4.7 turns priced as the
// anthropic-auto fallback; cached entries must re-parse once.
copilot: 'cli-shutdown-cost-v1-skills-source-provenance-v1-session-store-v3-chatsession-otel-skills-v1-otel-trace-metadata-once-v1-transcript-unknown-usage-v1-otel-workspace-project-v1-journal-request-input-v1-tokenless-turns-v1-store-row-output-v1-jetbrains-opus-4-7-v1',
// authoritative-usage-v4: persist one Grok session call from top-level
// authoritative totals, use modelUsage only for priced attribution, clamp
// reasoning per record, and label mixed sessions estimated.

View file

@ -4400,11 +4400,18 @@ describe('copilot provider - JetBrains model token scan', () => {
expect(findJetBrainsModelToken('"model":"gpt-5.6"')).toBe('gpt-5.6')
expect(findJetBrainsModelToken('gpt-5.4-mini beta')).toBe('gpt-5.4-mini')
expect(findJetBrainsModelToken('switched to claude-opus-4.8 today')).toBe('claude-opus-4-8')
expect(findJetBrainsModelToken('switched to claude-opus-4.7 today')).toBe('claude-opus-4-7')
expect(findJetBrainsModelToken('switched to claude-opus-4.6 today')).toBe('claude-opus-4-6')
expect(findJetBrainsModelToken('switched to claude-sonnet-4.6 today')).toBe('claude-sonnet-4-6')
expect(findJetBrainsModelToken('switched to claude-haiku-4.5 today')).toBe('claude-haiku-4-5')
})
it('prices a JetBrains claude-opus-4.7 chunk at the Opus 4.7 rate', () => {
const model = findJetBrainsModelToken('"model":"claude-opus-4.7"')
expect(model).toBe('claude-opus-4-7')
expect(calculateCost(model, 1_000_000, 1_000_000, 0, 0, 0)).toBeCloseTo(30, 6)
})
it('still matches tokens followed by sentence punctuation or file extensions', () => {
expect(findJetBrainsModelToken('switched to gpt-5. thanks')).toBe('gpt-5')
expect(findJetBrainsModelToken('see configs/gpt-5.json for details')).toBe('gpt-5')