Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
7.5 kB · 231 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232import type { BetaUsage as Usage } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs'import type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from 'src/services/analytics/index.js'import { logEvent } from 'src/services/analytics/index.js'import { setHasUnknownModelCost } from '../bootstrap/state.js'import { isFastModeEnabled } from './fastMode.js'import { CLAUDE_3_5_HAIKU_CONFIG, CLAUDE_3_5_V2_SONNET_CONFIG, CLAUDE_3_7_SONNET_CONFIG, CLAUDE_HAIKU_4_5_CONFIG, CLAUDE_OPUS_4_1_CONFIG, CLAUDE_OPUS_4_5_CONFIG, CLAUDE_OPUS_4_6_CONFIG, CLAUDE_OPUS_4_CONFIG, CLAUDE_SONNET_4_5_CONFIG, CLAUDE_SONNET_4_6_CONFIG, CLAUDE_SONNET_4_CONFIG,} from './model/configs.js'import { firstPartyNameToCanonical, getCanonicalName, getDefaultMainLoopModelSetting, type ModelShortName,} from './model/model.js'
// @see https://platform.claude.com/docs/en/about-claude/pricingexport type ModelCosts = { inputTokens: number outputTokens: number promptCacheWriteTokens: number promptCacheReadTokens: number webSearchRequests: number}
// Standard pricing tier for Sonnet models: $3 input / $15 output per Mtokexport const COST_TIER_3_15 = { inputTokens: 3, outputTokens: 15, promptCacheWriteTokens: 3.75, promptCacheReadTokens: 0.3, webSearchRequests: 0.01,} as const satisfies ModelCosts
// Pricing tier for Opus 4/4.1: $15 input / $75 output per Mtokexport const COST_TIER_15_75 = { inputTokens: 15, outputTokens: 75, promptCacheWriteTokens: 18.75, promptCacheReadTokens: 1.5, webSearchRequests: 0.01,} as const satisfies ModelCosts
// Pricing tier for Opus 4.5: $5 input / $25 output per Mtokexport const COST_TIER_5_25 = { inputTokens: 5, outputTokens: 25, promptCacheWriteTokens: 6.25, promptCacheReadTokens: 0.5, webSearchRequests: 0.01,} as const satisfies ModelCosts
// Fast mode pricing for Opus 4.6: $30 input / $150 output per Mtokexport const COST_TIER_30_150 = { inputTokens: 30, outputTokens: 150, promptCacheWriteTokens: 37.5, promptCacheReadTokens: 3, webSearchRequests: 0.01,} as const satisfies ModelCosts
// Pricing for Haiku 3.5: $0.80 input / $4 output per Mtokexport const COST_HAIKU_35 = { inputTokens: 0.8, outputTokens: 4, promptCacheWriteTokens: 1, promptCacheReadTokens: 0.08, webSearchRequests: 0.01,} as const satisfies ModelCosts
// Pricing for Haiku 4.5: $1 input / $5 output per Mtokexport const COST_HAIKU_45 = { inputTokens: 1, outputTokens: 5, promptCacheWriteTokens: 1.25, promptCacheReadTokens: 0.1, webSearchRequests: 0.01,} as const satisfies ModelCosts
const DEFAULT_UNKNOWN_MODEL_COST = COST_TIER_5_25
/** * Get the cost tier for Opus 4.6 based on fast mode. */export function getOpus46CostTier(fastMode: boolean): ModelCosts { if (isFastModeEnabled() && fastMode) { return COST_TIER_30_150 } return COST_TIER_5_25}
// @[MODEL LAUNCH]: Add a pricing entry for the new model below.// Costs from https://platform.claude.com/docs/en/about-claude/pricing// Web search cost: $10 per 1000 requests = $0.01 per requestexport const MODEL_COSTS: Record<ModelShortName, ModelCosts> = { [firstPartyNameToCanonical(CLAUDE_3_5_HAIKU_CONFIG.firstParty)]: COST_HAIKU_35, [firstPartyNameToCanonical(CLAUDE_HAIKU_4_5_CONFIG.firstParty)]: COST_HAIKU_45, [firstPartyNameToCanonical(CLAUDE_3_5_V2_SONNET_CONFIG.firstParty)]: COST_TIER_3_15, [firstPartyNameToCanonical(CLAUDE_3_7_SONNET_CONFIG.firstParty)]: COST_TIER_3_15, [firstPartyNameToCanonical(CLAUDE_SONNET_4_CONFIG.firstParty)]: COST_TIER_3_15, [firstPartyNameToCanonical(CLAUDE_SONNET_4_5_CONFIG.firstParty)]: COST_TIER_3_15, [firstPartyNameToCanonical(CLAUDE_SONNET_4_6_CONFIG.firstParty)]: COST_TIER_3_15, [firstPartyNameToCanonical(CLAUDE_OPUS_4_CONFIG.firstParty)]: COST_TIER_15_75, [firstPartyNameToCanonical(CLAUDE_OPUS_4_1_CONFIG.firstParty)]: COST_TIER_15_75, [firstPartyNameToCanonical(CLAUDE_OPUS_4_5_CONFIG.firstParty)]: COST_TIER_5_25, [firstPartyNameToCanonical(CLAUDE_OPUS_4_6_CONFIG.firstParty)]: COST_TIER_5_25,}
/** * Calculates the USD cost based on token usage and model cost configuration */function tokensToUSDCost(modelCosts: ModelCosts, usage: Usage): number { return ( (usage.input_tokens / 1_000_000) * modelCosts.inputTokens + (usage.output_tokens / 1_000_000) * modelCosts.outputTokens + ((usage.cache_read_input_tokens ?? 0) / 1_000_000) * modelCosts.promptCacheReadTokens + ((usage.cache_creation_input_tokens ?? 0) / 1_000_000) * modelCosts.promptCacheWriteTokens + (usage.server_tool_use?.web_search_requests ?? 0) * modelCosts.webSearchRequests )}
export function getModelCosts(model: string, usage: Usage): ModelCosts { const shortName = getCanonicalName(model)
// Check if this is an Opus 4.6 model with fast mode active. if ( shortName === firstPartyNameToCanonical(CLAUDE_OPUS_4_6_CONFIG.firstParty) ) { const isFastMode = usage.speed === 'fast' return getOpus46CostTier(isFastMode) }
const costs = MODEL_COSTS[shortName] if (!costs) { trackUnknownModelCost(model, shortName) return ( MODEL_COSTS[getCanonicalName(getDefaultMainLoopModelSetting())] ?? DEFAULT_UNKNOWN_MODEL_COST ) } return costs}
function trackUnknownModelCost(model: string, shortName: ModelShortName): void { logEvent('tengu_unknown_model_cost', { model: model as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, shortName: shortName as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, }) setHasUnknownModelCost()}
// Calculate the cost of a query in US dollars.// If the model's costs are not found, use the default model's costs.export function calculateUSDCost(resolvedModel: string, usage: Usage): number { const modelCosts = getModelCosts(resolvedModel, usage) return tokensToUSDCost(modelCosts, usage)}
/** * Calculate cost from raw token counts without requiring a full BetaUsage object. * Useful for side queries (e.g. classifier) that track token counts independently. */export function calculateCostFromTokens( model: string, tokens: { inputTokens: number outputTokens: number cacheReadInputTokens: number cacheCreationInputTokens: number },): number { const usage: Usage = { input_tokens: tokens.inputTokens, output_tokens: tokens.outputTokens, cache_read_input_tokens: tokens.cacheReadInputTokens, cache_creation_input_tokens: tokens.cacheCreationInputTokens, } as Usage return calculateUSDCost(model, usage)}
function formatPrice(price: number): string { // Format price: integers without decimals, others with 2 decimal places // e.g., 3 -> "$3", 0.8 -> "$0.80", 22.5 -> "$22.50" if (Number.isInteger(price)) { return `$${price}` } return `$${price.toFixed(2)}`}
/** * Format model costs as a pricing string for display * e.g., "$3/$15 per Mtok" */export function formatModelPricing(costs: ModelCosts): string { return `${formatPrice(costs.inputTokens)}/${formatPrice(costs.outputTokens)} per Mtok`}
/** * Get formatted pricing string for a model * Accepts either a short name or full model name * Returns undefined if model is not found */export function getModelPricingString(model: string): string | undefined { const shortName = getCanonicalName(model) const costs = MODEL_COSTS[shortName] if (!costs) return undefined return formatModelPricing(costs)}