fix(openai): preserve explicit GPT-5.6 cache write prices

This commit is contained in:
benjamin
2026-07-10 10:00:47 +08:00
parent 383f61d0e9
commit 062af81fb5
3 changed files with 51 additions and 1 deletions
+3 -1
View File
@@ -97,6 +97,7 @@ type ModelPricing struct {
OutputPricePerTokenPriority float64 // priority service tier 下每token输出价格 (USD)
CacheCreationPricePerToken float64 // 缓存创建每token价格 (USD)
CacheCreationPricePerTokenPriority float64 // priority service tier 下缓存创建每token价格 (USD)
CacheCreationPriceExplicit bool // 是否由渠道/区间定价显式设定(为 true 时即使 == 0 也不回退)
CacheReadPricePerToken float64 // 缓存读取每token价格 (USD)
CacheReadPricePerTokenPriority float64 // priority service tier 下缓存读取每token价格 (USD)
CacheCreation5mPrice float64 // 5分钟缓存创建每token价格 (USD)
@@ -825,6 +826,7 @@ func (s *BillingService) GetModelPricingWithChannel(model string, channelPricing
if channelPricing.CacheWritePrice != nil {
pricing.CacheCreationPricePerToken = *channelPricing.CacheWritePrice
pricing.CacheCreationPricePerTokenPriority = *channelPricing.CacheWritePrice
pricing.CacheCreationPriceExplicit = true
pricing.CacheCreation5mPrice = *channelPricing.CacheWritePrice
pricing.CacheCreation1hPrice = *channelPricing.CacheWritePrice
}
@@ -1100,7 +1102,7 @@ func (s *BillingService) applyModelSpecificPricingPolicy(model string, pricing *
}
needsLongContextPolicy := usesLegacyLongContextPricing &&
(pricing.LongContextInputThreshold <= 0 || pricing.LongContextInputMultiplier <= 0 || pricing.LongContextOutputMultiplier <= 0)
needsCacheCreationPolicy := isGPT56 && (pricing.CacheCreationPricePerToken <= 0 ||
needsCacheCreationPolicy := isGPT56 && !pricing.CacheCreationPriceExplicit && (pricing.CacheCreationPricePerToken <= 0 ||
(pricing.InputPricePerTokenPriority > 0 && pricing.CacheCreationPricePerTokenPriority <= 0))
if !needsLongContextPolicy && !needsCacheCreationPolicy {
return pricing
@@ -184,6 +184,7 @@ func (r *ModelPricingResolver) applyTokenOverrides(chPricing *ChannelModelPricin
if chPricing.CacheWritePrice != nil {
resolved.BasePricing.CacheCreationPricePerToken = *chPricing.CacheWritePrice
resolved.BasePricing.CacheCreationPricePerTokenPriority = *chPricing.CacheWritePrice
resolved.BasePricing.CacheCreationPriceExplicit = true
resolved.BasePricing.CacheCreation5mPrice = *chPricing.CacheWritePrice
resolved.BasePricing.CacheCreation1hPrice = *chPricing.CacheWritePrice
}
@@ -253,6 +254,7 @@ func intervalToModelPricing(iv *PricingInterval, supportsCacheBreakdown bool, ch
if iv.CacheWritePrice != nil {
pricing.CacheCreationPricePerToken = *iv.CacheWritePrice
pricing.CacheCreationPricePerTokenPriority = *iv.CacheWritePrice
pricing.CacheCreationPriceExplicit = true
pricing.CacheCreation5mPrice = *iv.CacheWritePrice
pricing.CacheCreation1hPrice = *iv.CacheWritePrice
}
@@ -114,6 +114,52 @@ func TestGetIntervalPricing_NoMatch_FallsBackToBase(t *testing.T) {
require.Equal(t, basePricing, result)
}
func TestGPT56ExplicitZeroCacheWritePriceIsPreserved(t *testing.T) {
bs := &BillingService{}
resolver := NewModelPricingResolver(nil, bs)
zero := 0.0
t.Run("flat channel price", func(t *testing.T) {
resolved := &ResolvedPricing{
Mode: BillingModeToken,
BasePricing: &ModelPricing{
InputPricePerToken: 5e-6,
OutputPricePerToken: 30e-6,
},
}
resolver.applyTokenOverrides(&ChannelModelPricing{CacheWritePrice: &zero}, resolved)
require.True(t, resolved.BasePricing.CacheCreationPriceExplicit)
cost, err := bs.CalculateCostUnified(CostInput{
Model: "gpt-5.6-sol",
Tokens: UsageTokens{CacheCreationTokens: 100},
RateMultiplier: 1,
Resolver: resolver,
Resolved: resolved,
})
require.NoError(t, err)
require.Zero(t, cost.CacheCreationCost)
})
t.Run("interval price", func(t *testing.T) {
pricing := intervalToModelPricing(&PricingInterval{CacheWritePrice: &zero}, false, nil)
require.True(t, pricing.CacheCreationPriceExplicit)
cost, err := bs.CalculateCostUnified(CostInput{
Model: "gpt-5.6-sol",
Tokens: UsageTokens{CacheCreationTokens: 100},
RateMultiplier: 1,
Resolver: resolver,
Resolved: &ResolvedPricing{
Mode: BillingModeToken,
BasePricing: pricing,
},
})
require.NoError(t, err)
require.Zero(t, cost.CacheCreationCost)
})
}
func TestGetRequestTierPrice(t *testing.T) {
bs := newTestBillingServiceForResolver()
r := NewModelPricingResolver(&ChannelService{}, bs)