From 82e5ea3ae60aa519c5d4bb990a624034be23689e Mon Sep 17 00:00:00 2001 From: octo-patch Date: Tue, 28 Apr 2026 10:35:34 +0800 Subject: [PATCH] fix: preserve extra request fields when model name is remapped (fixes #2295) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a channel has model mapping configured, the relay controller was re-serialising the request from the parsed GeneralOpenAIRequest struct. Any unknown fields sent by the client (e.g. enable_search, thinking, or other provider-specific params added via the OpenAI SDK extra_body mechanism) were silently dropped in that round-trip. Fix: for OpenAI-type channels where the only required transformation is a model name substitution, patch the model field directly in the raw request body instead of going through a full parse→marshal cycle. This preserves all extra fields so they reach the upstream provider unchanged. Co-Authored-By: Octopus --- relay/controller/text.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/relay/controller/text.go b/relay/controller/text.go index f912498a8e..169d52fe6c 100644 --- a/relay/controller/text.go +++ b/relay/controller/text.go @@ -9,6 +9,7 @@ import ( "github.com/gin-gonic/gin" + "github.com/songquanpeng/one-api/common" "github.com/songquanpeng/one-api/common/config" "github.com/songquanpeng/one-api/common/logger" "github.com/songquanpeng/one-api/relay" @@ -90,11 +91,28 @@ func RelayTextHelper(c *gin.Context) *model.ErrorWithStatusCode { func getRequestBody(c *gin.Context, meta *meta.Meta, textRequest *model.GeneralOpenAIRequest, adaptor adaptor.Adaptor) (io.Reader, error) { if !config.EnforceIncludeUsage && meta.APIType == apitype.OpenAI && - meta.OriginModelName == meta.ActualModelName && meta.ChannelType != channeltype.Baichuan && meta.ForcedSystemPrompt == "" { - // no need to convert request for openai - return c.Request.Body, nil + if meta.OriginModelName == meta.ActualModelName { + // no need to convert request for openai + return c.Request.Body, nil + } + // Only the model name was remapped; patch the original body so that any + // extra fields sent by the client (e.g. enable_search, extra_body params) + // are preserved instead of being dropped by the struct round-trip. + if originalBody, err := common.GetRequestBody(c); err == nil { + var bodyMap map[string]json.RawMessage + if jsonErr := json.Unmarshal(originalBody, &bodyMap); jsonErr == nil { + if modelJSON, marshalErr := json.Marshal(meta.ActualModelName); marshalErr == nil { + bodyMap["model"] = json.RawMessage(modelJSON) + if patchedBody, marshalErr := json.Marshal(bodyMap); marshalErr == nil { + logger.Debugf(c.Request.Context(), "patched model in request body: %s -> %s", meta.OriginModelName, meta.ActualModelName) + return bytes.NewBuffer(patchedBody), nil + } + } + } + } + // fallthrough to full conversion if patching fails } // get request body