@@ -57,6 +57,14 @@ enum CostUsagePricing {
5757 let cacheReadInputCostPerTokenAboveThreshold : Double ?
5858 }
5959
60+ private struct ClaudeCostTokens {
61+ let input : Int
62+ let cacheRead : Int
63+ let cacheCreation : Int
64+ let cacheCreation1h : Int
65+ let output : Int
66+ }
67+
6068 private static let codex : [ String : CodexPricing ] = [
6169 " gpt-5 " : CodexPricing (
6270 inputCostPerToken: 1.25e-6 ,
@@ -205,6 +213,16 @@ enum CostUsagePricing {
205213 }
206214
207215 private static let claude : [ String : ClaudePricing ] = [
216+ " claude-fable-5 " : ClaudePricing (
217+ inputCostPerToken: 1e-5 ,
218+ outputCostPerToken: 5e-5 ,
219+ cacheCreationInputCostPerToken: 1.25e-5 ,
220+ cacheReadInputCostPerToken: 1e-6 ,
221+ thresholdTokens: nil ,
222+ inputCostPerTokenAboveThreshold: nil ,
223+ outputCostPerTokenAboveThreshold: nil ,
224+ cacheCreationInputCostPerTokenAboveThreshold: nil ,
225+ cacheReadInputCostPerTokenAboveThreshold: nil ) ,
208226 " claude-haiku-4-5-20251001 " : ClaudePricing (
209227 inputCostPerToken: 1e-6 ,
210228 outputCostPerToken: 5e-6 ,
@@ -300,11 +318,11 @@ enum CostUsagePricing {
300318 outputCostPerToken: 1.5e-5 ,
301319 cacheCreationInputCostPerToken: 3.75e-6 ,
302320 cacheReadInputCostPerToken: 3e-7 ,
303- thresholdTokens: 200_000 ,
304- inputCostPerTokenAboveThreshold: 6e-6 ,
305- outputCostPerTokenAboveThreshold: 2.25e-5 ,
306- cacheCreationInputCostPerTokenAboveThreshold: 7.5e-6 ,
307- cacheReadInputCostPerTokenAboveThreshold: 6e-7 ) ,
321+ thresholdTokens: nil ,
322+ inputCostPerTokenAboveThreshold: nil ,
323+ outputCostPerTokenAboveThreshold: nil ,
324+ cacheCreationInputCostPerTokenAboveThreshold: nil ,
325+ cacheReadInputCostPerTokenAboveThreshold: nil ) ,
308326 " claude-sonnet-4-5-20250929 " : ClaudePricing (
309327 inputCostPerToken: 3e-6 ,
310328 outputCostPerToken: 1.5e-5 ,
@@ -347,6 +365,30 @@ enum CostUsagePricing {
347365 cacheReadInputCostPerTokenAboveThreshold: 6e-7 ) ,
348366 ]
349367
368+ private static let claudeFullContextStandardPricingCutoff = Date ( timeIntervalSince1970: 1_773_360_000 )
369+ private static let claudeHistoricalLongContext : [ String : ClaudePricing ] = [
370+ " claude-opus-4-6 " : ClaudePricing (
371+ inputCostPerToken: 5e-6 ,
372+ outputCostPerToken: 2.5e-5 ,
373+ cacheCreationInputCostPerToken: 6.25e-6 ,
374+ cacheReadInputCostPerToken: 5e-7 ,
375+ thresholdTokens: 200_000 ,
376+ inputCostPerTokenAboveThreshold: 1e-5 ,
377+ outputCostPerTokenAboveThreshold: 3.75e-5 ,
378+ cacheCreationInputCostPerTokenAboveThreshold: 1.25e-5 ,
379+ cacheReadInputCostPerTokenAboveThreshold: 1e-6 ) ,
380+ " claude-sonnet-4-6 " : ClaudePricing (
381+ inputCostPerToken: 3e-6 ,
382+ outputCostPerToken: 1.5e-5 ,
383+ cacheCreationInputCostPerToken: 3.75e-6 ,
384+ cacheReadInputCostPerToken: 3e-7 ,
385+ thresholdTokens: 200_000 ,
386+ inputCostPerTokenAboveThreshold: 6e-6 ,
387+ outputCostPerTokenAboveThreshold: 2.25e-5 ,
388+ cacheCreationInputCostPerTokenAboveThreshold: 7.5e-6 ,
389+ cacheReadInputCostPerTokenAboveThreshold: 6e-7 ) ,
390+ ]
391+
350392 private static let codexModelsDevProviderID = " openai "
351393 private static let claudeModelsDevProviderID = " anthropic "
352394
@@ -514,10 +556,29 @@ enum CostUsagePricing {
514556 inputTokens: Int ,
515557 cacheReadInputTokens: Int ,
516558 cacheCreationInputTokens: Int ,
559+ cacheCreationInputTokens1h: Int = 0 ,
517560 outputTokens: Int ,
561+ pricingDate: Date ? = nil ,
518562 modelsDevCatalog: ModelsDevCatalog ? = nil ,
519563 modelsDevCacheRoot: URL ? = nil ) -> Double ?
520564 {
565+ let tokens = ClaudeCostTokens (
566+ input: inputTokens,
567+ cacheRead: cacheReadInputTokens,
568+ cacheCreation: cacheCreationInputTokens,
569+ cacheCreation1h: cacheCreationInputTokens1h,
570+ output: outputTokens)
571+ let key = self . normalizeClaudeModel ( model)
572+ if let pricingDate,
573+ let historicalPricing = self . claudeHistoricalLongContext [ key] ,
574+ let currentPricing = self . claude [ key]
575+ {
576+ return self . claudeCostUSD (
577+ pricing: pricingDate < self . claudeFullContextStandardPricingCutoff
578+ ? historicalPricing
579+ : currentPricing,
580+ tokens: tokens)
581+ }
521582 if let lookup = self . modelsDevLookup (
522583 providerID: self . claudeModelsDevProviderID,
523584 model: model,
@@ -526,64 +587,50 @@ enum CostUsagePricing {
526587 {
527588 return self . claudeCostUSD (
528589 pricing: lookup. pricing,
529- inputTokens: inputTokens,
530- cacheReadInputTokens: cacheReadInputTokens,
531- cacheCreationInputTokens: cacheCreationInputTokens,
532- outputTokens: outputTokens)
590+ tokens: tokens)
533591 }
534592
535- let key = self . normalizeClaudeModel ( model)
536593 guard let pricing = self . claude [ key] else { return nil }
537594 return self . claudeCostUSD (
538595 pricing: pricing,
539- inputTokens: inputTokens,
540- cacheReadInputTokens: cacheReadInputTokens,
541- cacheCreationInputTokens: cacheCreationInputTokens,
542- outputTokens: outputTokens)
596+ tokens: tokens)
543597 }
544598
545599 private static func claudeCostUSD(
546600 pricing: ClaudePricing ,
547- inputTokens: Int ,
548- cacheReadInputTokens: Int ,
549- cacheCreationInputTokens: Int ,
550- outputTokens: Int ) -> Double
601+ tokens: ClaudeCostTokens ) -> Double
551602 {
552- func tiered( _ tokens: Int , base: Double , above: Double ? , threshold: Int ? ) -> Double {
553- guard let threshold, let above else { return Double ( tokens) * base }
554- let below = min ( tokens, threshold)
555- let over = max ( tokens - threshold, 0 )
556- return Double ( below) * base + Double( over) * above
557- }
603+ let input = max ( 0 , tokens. input)
604+ let cacheRead = max ( 0 , tokens. cacheRead)
605+ let cacheCreationTotal = max ( 0 , tokens. cacheCreation)
606+ let cacheCreation1h = min ( max ( 0 , tokens. cacheCreation1h) , cacheCreationTotal)
607+ let cacheCreation5m = cacheCreationTotal - cacheCreation1h
608+ let usesLongContextRates = pricing. thresholdTokens. map {
609+ input + cacheRead + cacheCreationTotal > $0
610+ } ?? false
611+ let inputRate = usesLongContextRates
612+ ? pricing. inputCostPerTokenAboveThreshold ?? pricing. inputCostPerToken
613+ : pricing. inputCostPerToken
614+ let cacheReadRate = usesLongContextRates
615+ ? pricing. cacheReadInputCostPerTokenAboveThreshold ?? pricing. cacheReadInputCostPerToken
616+ : pricing. cacheReadInputCostPerToken
617+ let cacheCreation5mRate = usesLongContextRates
618+ ? pricing. cacheCreationInputCostPerTokenAboveThreshold ?? pricing. cacheCreationInputCostPerToken
619+ : pricing. cacheCreationInputCostPerToken
620+ let outputRate = usesLongContextRates
621+ ? pricing. outputCostPerTokenAboveThreshold ?? pricing. outputCostPerToken
622+ : pricing. outputCostPerToken
558623
559- return tiered (
560- max ( 0 , inputTokens) ,
561- base: pricing. inputCostPerToken,
562- above: pricing. inputCostPerTokenAboveThreshold,
563- threshold: pricing. thresholdTokens)
564- + tiered(
565- max ( 0 , cacheReadInputTokens) ,
566- base: pricing. cacheReadInputCostPerToken,
567- above: pricing. cacheReadInputCostPerTokenAboveThreshold,
568- threshold: pricing. thresholdTokens)
569- + tiered(
570- max ( 0 , cacheCreationInputTokens) ,
571- base: pricing. cacheCreationInputCostPerToken,
572- above: pricing. cacheCreationInputCostPerTokenAboveThreshold,
573- threshold: pricing. thresholdTokens)
574- + tiered(
575- max ( 0 , outputTokens) ,
576- base: pricing. outputCostPerToken,
577- above: pricing. outputCostPerTokenAboveThreshold,
578- threshold: pricing. thresholdTokens)
624+ return Double ( input) * inputRate
625+ + Double( cacheRead) * cacheReadRate
626+ + Double( cacheCreation5m) * cacheCreation5mRate
627+ + Double( cacheCreation1h) * inputRate * 2
628+ + Double( max ( 0 , tokens. output) ) * outputRate
579629 }
580630
581631 private static func claudeCostUSD(
582632 pricing: ModelsDevPricingInfo ,
583- inputTokens: Int ,
584- cacheReadInputTokens: Int ,
585- cacheCreationInputTokens: Int ,
586- outputTokens: Int ) -> Double
633+ tokens: ClaudeCostTokens ) -> Double
587634 {
588635 self . claudeCostUSD (
589636 pricing: ClaudePricing (
@@ -596,10 +643,7 @@ enum CostUsagePricing {
596643 outputCostPerTokenAboveThreshold: pricing. outputCostPerTokenAboveThreshold,
597644 cacheCreationInputCostPerTokenAboveThreshold: pricing. cacheCreationInputCostPerTokenAboveThreshold,
598645 cacheReadInputCostPerTokenAboveThreshold: pricing. cacheReadInputCostPerTokenAboveThreshold) ,
599- inputTokens: inputTokens,
600- cacheReadInputTokens: cacheReadInputTokens,
601- cacheCreationInputTokens: cacheCreationInputTokens,
602- outputTokens: outputTokens)
646+ tokens: tokens)
603647 }
604648
605649 static func modelsDevCatalog( now: Date = Date ( ) , cacheRoot: URL ? = nil ) -> ModelsDevCatalog ? {
0 commit comments