refactor: wire session analyzer and CostSection to shared pricing

Replace the hardcoded MODEL_PRICING table and costUsd() function in
sessionAnalyzer.ts with calculateMessageCost() and getDisplayPricing()
from the shared pricing module. Re-export getDisplayPricing as getPricing
for backward compat with CostSection. Replace the ModelPricing interface
with a type re-export of DisplayPricing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Paul Holstein 2026-02-23 12:07:50 -05:00
parent 3e6d02f317
commit ec9b3412fa
2 changed files with 6 additions and 84 deletions

View file

@ -20,12 +20,7 @@ import type {
// Pricing // Pricing
// ============================================================================= // =============================================================================
export interface ModelPricing { export type { DisplayPricing as ModelPricing } from '@shared/utils/pricing';
input: number;
output: number;
cache_read: number;
cache_creation: number;
}
// ============================================================================= // =============================================================================
// Report Sections // Report Sections

View file

@ -22,6 +22,7 @@ import {
detectModelMismatch, detectModelMismatch,
detectSwitchPattern, detectSwitchPattern,
} from '@renderer/utils/reportAssessments'; } from '@renderer/utils/reportAssessments';
import { calculateMessageCost } from '@shared/utils/pricing';
import type { import type {
AgentTreeNode, AgentTreeNode,
@ -29,7 +30,6 @@ import type {
GitCommit, GitCommit,
IdleGap, IdleGap,
KeyEvent, KeyEvent,
ModelPricing,
ModelSwitch, ModelSwitch,
ModelTokenStats, ModelTokenStats,
OutOfScopeFindings, OutOfScopeFindings,
@ -53,81 +53,8 @@ import type {
ToolCall, ToolCall,
} from '@shared/types'; } from '@shared/types';
// ============================================================================= // Re-export getDisplayPricing as getPricing for backward compat with CostSection
// Pricing Table (USD per 1M tokens) export { getDisplayPricing as getPricing } from '@shared/utils/pricing';
// =============================================================================
const MODEL_PRICING: Record<string, ModelPricing> = {
'opus-4': {
input: 15.0,
output: 75.0,
cache_read: 1.5,
cache_creation: 18.75,
},
'sonnet-4': {
input: 3.0,
output: 15.0,
cache_read: 0.3,
cache_creation: 3.75,
},
'haiku-4': {
input: 0.8,
output: 4.0,
cache_read: 0.08,
cache_creation: 1.0,
},
'opus-3': {
input: 15.0,
output: 75.0,
cache_read: 1.5,
cache_creation: 18.75,
},
'sonnet-3': {
input: 3.0,
output: 15.0,
cache_read: 0.3,
cache_creation: 3.75,
},
'haiku-3': {
input: 0.25,
output: 1.25,
cache_read: 0.03,
cache_creation: 0.3,
},
};
const DEFAULT_PRICING: ModelPricing = {
input: 3.0,
output: 15.0,
cache_read: 0.3,
cache_creation: 3.75,
};
export function getPricing(modelName: string): ModelPricing {
const nameTokens: string[] = modelName.toLowerCase().match(/[a-z0-9]+/g) ?? [];
for (const [key, pricing] of Object.entries(MODEL_PRICING)) {
const keyTokens: string[] = key.match(/[a-z0-9]+/g) ?? [];
if (keyTokens.every((t) => nameTokens.includes(t))) return pricing;
}
return DEFAULT_PRICING;
}
function costUsd(
modelName: string,
inputTok: number,
outputTok: number,
cacheReadTok: number,
cacheCreationTok: number
): number {
const p = getPricing(modelName);
return (
(inputTok * p.input +
outputTok * p.output +
cacheReadTok * p.cache_read +
cacheCreationTok * p.cache_creation) /
1_000_000
);
}
// ============================================================================= // =============================================================================
// Helpers // Helpers
@ -473,7 +400,7 @@ export function analyzeSession(detail: SessionDetail): SessionReport {
stats.cacheCreation += cc; stats.cacheCreation += cc;
stats.cacheRead += cr; stats.cacheRead += cr;
const callCost = costUsd(model, inpTok, outTok, cr, cc); const callCost = calculateMessageCost(model, inpTok, outTok, cr, cc);
stats.costUsd += callCost; stats.costUsd += callCost;
parentCost += callCost; parentCost += callCost;
@ -897,7 +824,7 @@ export function analyzeSession(detail: SessionDetail): SessionReport {
proc.messages.find((m: ParsedMessage) => m.type === 'assistant' && m.model)?.model ?? proc.messages.find((m: ParsedMessage) => m.type === 'assistant' && m.model)?.model ??
'default (inherits parent)'; 'default (inherits parent)';
// Compute cost from subagent token breakdown (proc.metrics.costUsd is not populated upstream) // Compute cost from subagent token breakdown (proc.metrics.costUsd is not populated upstream)
const computedCost = costUsd( const computedCost = calculateMessageCost(
subagentModel, subagentModel,
proc.metrics.inputTokens, proc.metrics.inputTokens,
proc.metrics.outputTokens, proc.metrics.outputTokens,