fix: validate empty intervals + antigravity platform pricing match

- Backend: reject intervals with all-null price fields on save
- Backend: filterValidIntervals skips empty intervals in pricing resolver
- Frontend: red border + asterisk on empty interval rows
- Backend: antigravity groups now match anthropic/gemini channel pricing
This commit is contained in:
erio
2026-04-01 22:03:00 +08:00
parent 8d25335b01
commit 2355029dc1
3 changed files with 53 additions and 7 deletions

View File

@@ -106,9 +106,12 @@ func (r *ModelPricingResolver) applyChannelOverrides(ctx context.Context, groupI
// applyTokenOverrides 应用 token 模式的渠道覆盖
func (r *ModelPricingResolver) applyTokenOverrides(chPricing *ChannelModelPricing, resolved *ResolvedPricing) {
// 如果有区间定价,使用区间
if len(chPricing.Intervals) > 0 {
resolved.Intervals = chPricing.Intervals
// 过滤掉所有价格字段都为空的无效 interval
validIntervals := filterValidIntervals(chPricing.Intervals)
// 如果有有效的区间定价,使用区间
if len(validIntervals) > 0 {
resolved.Intervals = validIntervals
return
}
@@ -147,6 +150,20 @@ func (r *ModelPricingResolver) applyRequestTierOverrides(chPricing *ChannelModel
}
}
// filterValidIntervals 过滤掉所有价格字段都为空的无效 interval。
// 前端可能创建了只有 min/max 但无价格的空 interval。
func filterValidIntervals(intervals []PricingInterval) []PricingInterval {
var valid []PricingInterval
for _, iv := range intervals {
if iv.InputPrice != nil || iv.OutputPrice != nil ||
iv.CacheWritePrice != nil || iv.CacheReadPrice != nil ||
iv.PerRequestPrice != nil {
valid = append(valid, iv)
}
}
return valid
}
// GetIntervalPricing 根据 context token 数获取区间定价。
// 如果有区间列表,找到匹配区间并构造 ModelPricing否则直接返回 BasePricing。
func (r *ModelPricingResolver) GetIntervalPricing(resolved *ResolvedPricing, totalContextTokens int) *ModelPricing {