diff --git a/backend/internal/service/channel_monitor_service.go b/backend/internal/service/channel_monitor_service.go index 7050e141..6eec0ae0 100644 --- a/backend/internal/service/channel_monitor_service.go +++ b/backend/internal/service/channel_monitor_service.go @@ -107,7 +107,7 @@ func (s *ChannelMonitorService) Create(ctx context.Context, p ChannelMonitorCrea if err := validateCreateParams(p); err != nil { return nil, err } - if err := validateBodyModeParams(p.BodyOverrideMode, p.BodyOverride); err != nil { + if err := validateBodyModeForProtocol(p.Provider, p.APIMode, p.BodyOverrideMode, p.BodyOverride); err != nil { return nil, err } if err := validateExtraHeaders(p.ExtraHeaders); err != nil { @@ -120,6 +120,7 @@ func (s *ChannelMonitorService) Create(ctx context.Context, p ChannelMonitorCrea m := &ChannelMonitor{ Name: strings.TrimSpace(p.Name), Provider: p.Provider, + APIMode: defaultAPIMode(p.APIMode), Endpoint: normalizeEndpoint(p.Endpoint), APIKey: encrypted, // 注意:传入 repository 时该字段为密文 PrimaryModel: strings.TrimSpace(p.PrimaryModel), @@ -150,6 +151,9 @@ func validateCreateParams(p ChannelMonitorCreateParams) error { if err := validateProvider(p.Provider); err != nil { return err } + if err := validateAPIMode(p.Provider, p.APIMode); err != nil { + return err + } if err := validateInterval(p.IntervalSeconds); err != nil { return err } @@ -298,6 +302,7 @@ func (s *ChannelMonitorService) runChecksConcurrent(ctx context.Context, m *Chan // 所有模型共用同一份 CheckOptions(来自监控的快照字段)。 opts := &CheckOptions{ + APIMode: m.APIMode, ExtraHeaders: m.ExtraHeaders, BodyOverrideMode: m.BodyOverrideMode, BodyOverride: m.BodyOverride, @@ -469,6 +474,7 @@ func (s *ChannelMonitorService) decryptInPlace(m *ChannelMonitor) { // 行数稍超过 30:这是逐字段平铺的 dispatcher,每个 if 都是 1-3 行的"非 nil 则覆盖"模式, // 拆分反而会增加跳转噪音、影响可读性,故保留为单函数。 func applyMonitorUpdate(existing *ChannelMonitor, p ChannelMonitorUpdateParams) error { + providerChanged := false if p.Name != nil { existing.Name = strings.TrimSpace(*p.Name) } @@ -477,6 +483,7 @@ func applyMonitorUpdate(existing *ChannelMonitor, p ChannelMonitorUpdateParams) return err } existing.Provider = *p.Provider + providerChanged = true } if p.Endpoint != nil { if err := validateEndpoint(*p.Endpoint); err != nil { @@ -502,11 +509,11 @@ func applyMonitorUpdate(existing *ChannelMonitor, p ChannelMonitorUpdateParams) } existing.IntervalSeconds = *p.IntervalSeconds } - return applyMonitorAdvancedUpdate(existing, p) + return applyMonitorAdvancedUpdate(existing, p, providerChanged) } // applyMonitorAdvancedUpdate 处理自定义请求快照相关字段,从 applyMonitorUpdate 拆出避免过长。 -func applyMonitorAdvancedUpdate(existing *ChannelMonitor, p ChannelMonitorUpdateParams) error { +func applyMonitorAdvancedUpdate(existing *ChannelMonitor, p ChannelMonitorUpdateParams, providerChanged bool) error { if p.ClearTemplate { existing.TemplateID = nil } else if p.TemplateID != nil { @@ -519,6 +526,15 @@ func applyMonitorAdvancedUpdate(existing *ChannelMonitor, p ChannelMonitorUpdate } existing.ExtraHeaders = emptyHeadersIfNil(*p.ExtraHeaders) } + newAPIMode := defaultAPIMode(existing.APIMode) + if p.APIMode != nil { + newAPIMode = defaultAPIMode(*p.APIMode) + } else if existing.Provider != MonitorProviderOpenAI { + newAPIMode = MonitorAPIModeChatCompletions + } + if err := validateAPIMode(existing.Provider, newAPIMode); err != nil { + return err + } // BodyOverrideMode / BodyOverride 联合校验,和模板一致。 newMode := existing.BodyOverrideMode newBody := existing.BodyOverride @@ -528,12 +544,13 @@ func applyMonitorAdvancedUpdate(existing *ChannelMonitor, p ChannelMonitorUpdate if p.BodyOverride != nil { newBody = *p.BodyOverride } - if p.BodyOverrideMode != nil || p.BodyOverride != nil { - if err := validateBodyModeParams(newMode, newBody); err != nil { + if providerChanged || p.APIMode != nil || p.BodyOverrideMode != nil || p.BodyOverride != nil { + if err := validateBodyModeForProtocol(existing.Provider, newAPIMode, newMode, newBody); err != nil { return err } existing.BodyOverrideMode = defaultBodyMode(newMode) existing.BodyOverride = newBody } + existing.APIMode = newAPIMode return nil }