fix: websearch features_config cleanup and pricing rules validation
- Fix web_search_emulation toggle: explicitly write false for disabled platforms instead of leaving stale true from cloned features_config - Extract validatePricingEntries from validateChannelConfig for reuse - Validate account_stats_pricing_rules[].pricing in both Create and Update paths (negative prices, bad intervals, missing per_request price)
This commit is contained in:
@@ -566,15 +566,21 @@ func ReplaceModelInBody(body []byte, newModel string) []byte {
|
||||
// validateChannelConfig 校验渠道的定价和映射配置(冲突检测 + 区间校验 + 计费模式校验)。
|
||||
// Create 和 Update 共用此函数,避免重复。
|
||||
func validateChannelConfig(pricing []ChannelModelPricing, mapping map[string]map[string]string) error {
|
||||
if err := validatePricingEntries(pricing); err != nil {
|
||||
return err
|
||||
}
|
||||
return validateNoConflictingMappings(mapping)
|
||||
}
|
||||
|
||||
// validatePricingEntries 校验定价条目(冲突检测 + 区间校验 + 计费模式校验),
|
||||
// 同时用于主渠道定价和 account_stats_pricing_rules 的内部定价。
|
||||
func validatePricingEntries(pricing []ChannelModelPricing) error {
|
||||
if err := validateNoConflictingModels(pricing); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validatePricingIntervals(pricing); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateNoConflictingMappings(mapping); err != nil {
|
||||
return err
|
||||
}
|
||||
return validatePricingBillingMode(pricing)
|
||||
}
|
||||
|
||||
@@ -684,6 +690,11 @@ func (s *ChannelService) Create(ctx context.Context, input *CreateChannelInput)
|
||||
if err := validateChannelConfig(channel.ModelPricing, channel.ModelMapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i, rule := range channel.AccountStatsPricingRules {
|
||||
if err := validatePricingEntries(rule.Pricing); err != nil {
|
||||
return nil, fmt.Errorf("account stats pricing rule #%d: %w", i+1, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.repo.Create(ctx, channel); err != nil {
|
||||
return nil, fmt.Errorf("create channel: %w", err)
|
||||
@@ -712,6 +723,11 @@ func (s *ChannelService) Update(ctx context.Context, id int64, input *UpdateChan
|
||||
if err := validateChannelConfig(channel.ModelPricing, channel.ModelMapping); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i, rule := range channel.AccountStatsPricingRules {
|
||||
if err := validatePricingEntries(rule.Pricing); err != nil {
|
||||
return nil, fmt.Errorf("account stats pricing rule #%d: %w", i+1, err)
|
||||
}
|
||||
}
|
||||
|
||||
oldGroupIDs := s.getOldGroupIDs(ctx, id)
|
||||
|
||||
|
||||
@@ -1032,15 +1032,19 @@ function formToAPI(): { group_ids: number[], model_pricing: ChannelModelPricing[
|
||||
}
|
||||
|
||||
// Collect web_search_emulation (only anthropic platform supports it)
|
||||
// Always write the key so that disabling in the UI correctly sets platform to false,
|
||||
// rather than leaving a stale true value from the cloned features_config.
|
||||
const wsEmulation: Record<string, boolean> = {}
|
||||
for (const section of form.platforms) {
|
||||
if (!section.enabled) continue
|
||||
if (section.web_search_emulation && section.platform === 'anthropic') {
|
||||
wsEmulation[section.platform] = true
|
||||
if (section.platform === 'anthropic') {
|
||||
wsEmulation[section.platform] = !!section.web_search_emulation
|
||||
}
|
||||
}
|
||||
if (Object.keys(wsEmulation).length > 0) {
|
||||
featuresConfig.web_search_emulation = wsEmulation
|
||||
} else {
|
||||
delete featuresConfig.web_search_emulation
|
||||
}
|
||||
|
||||
return { group_ids, model_pricing, model_mapping, features_config: featuresConfig }
|
||||
|
||||
Reference in New Issue
Block a user