Преглед изворни кода

feat: 移植上游 Param Override 增强系统

从上游移植 override.go 的完整增强功能(603行→2057行),包括:

新增 9 种 Operation Mode:
- return_error: 规则直接返回 HTTP 错误中断请求
- prune_objects: 按 JSON Schema 过滤数组元素
- set_header / delete_header / copy_header / move_header: 动态管理上游请求头
- pass_headers: 透传下游请求头到上游
- sync_fields: 请求体不同路径间同步字段值
- 通配符路径支持: messages.*.role 等

新增核心模块:
- Header Override 系统:从上下文取值、正则匹配、列表追加
- Audit 审计系统:关键操作自动记录到 RelayInfo.ParamOverrideAudit
- Return Error 机制:含状态码/错误类型/跳过重试控制
- Legacy 兼容层:同时执行旧格式和新格式 param override
- RelayInfo 集成:丰富上下文(retry_index、last_error、request_headers 等)

RelayInfo 新增字段:RetryIndex, LastError, RequestHeaders,
RuntimeHeadersOverride, UseRuntimeHeadersOverride, ParamOverrideAudit

所有 handler 统一使用 ApplyParamOverrideWithRelayInfo,
全部测试通过(100+ test cases)。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat/alipay-payment
fengsilin пре 4 недеља
родитељ
комит
97485bfede
11 измењених фајлова са 2988 додато и 186 уклоњено
  1. +1
    -2
      relay/chat_completions_via_responses.go
  2. +1
    -1
      relay/claude_handler.go
  3. +1584
    -130
      relay/common/override.go
  4. +1368
    -47
      relay/common/override_test.go
  5. +28
    -0
      relay/common/relay_info.go
  6. +1
    -1
      relay/compatible_handler.go
  7. +1
    -1
      relay/embedding_handler.go
  8. +1
    -1
      relay/gemini_handler.go
  9. +1
    -1
      relay/image_handler.go
  10. +1
    -1
      relay/rerank_handler.go
  11. +1
    -1
      relay/responses_handler.go

+ 1
- 2
relay/chat_completions_via_responses.go Прегледај датотеку

@@ -70,7 +70,6 @@ func applySystemPromptIfNeeded(c *gin.Context, info *relaycommon.RelayInfo, requ
} }


func chatCompletionsViaResponses(c *gin.Context, info *relaycommon.RelayInfo, adaptor channel.Adaptor, request *dto.GeneralOpenAIRequest) (*dto.Usage, *types.NewAPIError) { func chatCompletionsViaResponses(c *gin.Context, info *relaycommon.RelayInfo, adaptor channel.Adaptor, request *dto.GeneralOpenAIRequest) (*dto.Usage, *types.NewAPIError) {
overrideCtx := relaycommon.BuildParamOverrideContext(info)
chatJSON, err := common.Marshal(request) chatJSON, err := common.Marshal(request)
if err != nil { if err != nil {
return nil, types.NewError(err, types.ErrorCodeConvertRequestFailed, types.ErrOptionWithSkipRetry()) return nil, types.NewError(err, types.ErrorCodeConvertRequestFailed, types.ErrOptionWithSkipRetry())
@@ -82,7 +81,7 @@ func chatCompletionsViaResponses(c *gin.Context, info *relaycommon.RelayInfo, ad
} }


if len(info.ParamOverride) > 0 { if len(info.ParamOverride) > 0 {
chatJSON, err = relaycommon.ApplyParamOverride(chatJSON, info.ParamOverride, overrideCtx)
chatJSON, err = relaycommon.ApplyParamOverrideWithRelayInfo(chatJSON, info)
if err != nil { if err != nil {
return nil, types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) return nil, types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry())
} }


+ 1
- 1
relay/claude_handler.go Прегледај датотеку

@@ -153,7 +153,7 @@ func ClaudeHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *typ


// apply param override // apply param override
if len(info.ParamOverride) > 0 { if len(info.ParamOverride) > 0 {
jsonData, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, relaycommon.BuildParamOverrideContext(info))
jsonData, err = relaycommon.ApplyParamOverrideWithRelayInfo(jsonData, info)
if err != nil { if err != nil {
return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry())
} }


+ 1584
- 130
relay/common/override.go
Разлика између датотеке није приказан због своје велике величине
Прегледај датотеку


+ 1368
- 47
relay/common/override_test.go
Разлика између датотеке није приказан због своје велике величине
Прегледај датотеку


+ 28
- 0
relay/common/relay_info.go Прегледај датотеку

@@ -144,6 +144,12 @@ type RelayInfo struct {
SubscriptionAmountUsedAfterPreConsume int64 SubscriptionAmountUsedAfterPreConsume int64
IsClaudeBetaQuery bool // /v1/messages?beta=true IsClaudeBetaQuery bool // /v1/messages?beta=true
IsChannelTest bool // channel test request IsChannelTest bool // channel test request
RetryIndex int
LastError *types.NewAPIError
RequestHeaders map[string]string
RuntimeHeadersOverride map[string]interface{}
UseRuntimeHeadersOverride bool
ParamOverrideAudit []string


PriceData types.PriceData PriceData types.PriceData


@@ -473,6 +479,7 @@ func genBaseRelayInfo(c *gin.Context, request dto.Request) *RelayInfo {
//promptTokens: common.GetContextKeyInt(c, constant.ContextKeyPromptTokens), //promptTokens: common.GetContextKeyInt(c, constant.ContextKeyPromptTokens),
estimatePromptTokens: common.GetContextKeyInt(c, constant.ContextKeyEstimatedTokens), estimatePromptTokens: common.GetContextKeyInt(c, constant.ContextKeyEstimatedTokens),
}, },
RequestHeaders: cloneRequestHeaders(c),
} }


if info.RelayMode == relayconstant.RelayModeUnknown { if info.RelayMode == relayconstant.RelayModeUnknown {
@@ -493,6 +500,27 @@ func genBaseRelayInfo(c *gin.Context, request dto.Request) *RelayInfo {
return info return info
} }


func cloneRequestHeaders(c *gin.Context) map[string]string {
if c == nil || c.Request == nil {
return nil
}
if len(c.Request.Header) == 0 {
return nil
}
headers := make(map[string]string, len(c.Request.Header))
for key := range c.Request.Header {
value := strings.TrimSpace(c.Request.Header.Get(key))
if value == "" {
continue
}
headers[key] = value
}
if len(headers) == 0 {
return nil
}
return headers
}

func GenRelayInfo(c *gin.Context, relayFormat types.RelayFormat, request dto.Request, ws *websocket.Conn) (*RelayInfo, error) { func GenRelayInfo(c *gin.Context, relayFormat types.RelayFormat, request dto.Request, ws *websocket.Conn) (*RelayInfo, error) {
var info *RelayInfo var info *RelayInfo
var err error var err error


+ 1
- 1
relay/compatible_handler.go Прегледај датотеку

@@ -172,7 +172,7 @@ func TextHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *types


// apply param override // apply param override
if len(info.ParamOverride) > 0 { if len(info.ParamOverride) > 0 {
jsonData, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, relaycommon.BuildParamOverrideContext(info))
jsonData, err = relaycommon.ApplyParamOverrideWithRelayInfo(jsonData, info)
if err != nil { if err != nil {
return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry())
} }


+ 1
- 1
relay/embedding_handler.go Прегледај датотеку

@@ -52,7 +52,7 @@ func EmbeddingHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *
} }


if len(info.ParamOverride) > 0 { if len(info.ParamOverride) > 0 {
jsonData, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, relaycommon.BuildParamOverrideContext(info))
jsonData, err = relaycommon.ApplyParamOverrideWithRelayInfo(jsonData, info)
if err != nil { if err != nil {
return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry())
} }


+ 1
- 1
relay/gemini_handler.go Прегледај датотеку

@@ -157,7 +157,7 @@ func GeminiHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *typ


// apply param override // apply param override
if len(info.ParamOverride) > 0 { if len(info.ParamOverride) > 0 {
jsonData, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, relaycommon.BuildParamOverrideContext(info))
jsonData, err = relaycommon.ApplyParamOverrideWithRelayInfo(jsonData, info)
if err != nil { if err != nil {
return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry())
} }


+ 1
- 1
relay/image_handler.go Прегледај датотеку

@@ -70,7 +70,7 @@ func ImageHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *type


// apply param override // apply param override
if len(info.ParamOverride) > 0 { if len(info.ParamOverride) > 0 {
jsonData, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, relaycommon.BuildParamOverrideContext(info))
jsonData, err = relaycommon.ApplyParamOverrideWithRelayInfo(jsonData, info)
if err != nil { if err != nil {
return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry())
} }


+ 1
- 1
relay/rerank_handler.go Прегледај датотеку

@@ -61,7 +61,7 @@ func RerankHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *typ


// apply param override // apply param override
if len(info.ParamOverride) > 0 { if len(info.ParamOverride) > 0 {
jsonData, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, relaycommon.BuildParamOverrideContext(info))
jsonData, err = relaycommon.ApplyParamOverrideWithRelayInfo(jsonData, info)
if err != nil { if err != nil {
return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry())
} }


+ 1
- 1
relay/responses_handler.go Прегледај датотеку

@@ -96,7 +96,7 @@ func ResponsesHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *


// apply param override // apply param override
if len(info.ParamOverride) > 0 { if len(info.ParamOverride) > 0 {
jsonData, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, relaycommon.BuildParamOverrideContext(info))
jsonData, err = relaycommon.ApplyParamOverrideWithRelayInfo(jsonData, info)
if err != nil { if err != nil {
return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry())
} }


Loading…
Откажи
Сачувај