diff --git a/relay/channel/openai/adaptor.go b/relay/channel/openai/adaptor.go index 01a5fa97..8f81ab8c 100644 --- a/relay/channel/openai/adaptor.go +++ b/relay/channel/openai/adaptor.go @@ -67,7 +67,7 @@ func (a *Adaptor) ConvertClaudeRequest(c *gin.Context, info *relaycommon.RelayIn if err != nil { return nil, err } - if info.SupportStreamOptions { + if info.SupportStreamOptions && info.IsStream { aiRequest.StreamOptions = &dto.StreamOptions{ IncludeUsage: true, } @@ -188,6 +188,7 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn if len(request.Usage) == 0 { request.Usage = json.RawMessage(`{"include":true}`) } + // 适配 OpenRouter 的 thinking 后缀 if strings.HasSuffix(info.UpstreamModelName, "-thinking") { info.UpstreamModelName = strings.TrimSuffix(info.UpstreamModelName, "-thinking") request.Model = info.UpstreamModelName @@ -195,7 +196,7 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn reasoning := map[string]any{ "enabled": true, } - if request.ReasoningEffort != "" { + if request.ReasoningEffort != "" && request.ReasoningEffort != "none" { reasoning["effort"] = request.ReasoningEffort } marshal, err := common.Marshal(reasoning) @@ -204,6 +205,23 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn } request.Reasoning = marshal } + } else { + if len(request.Reasoning) == 0 { + // 适配 OpenAI 的 ReasoningEffort 格式 + if request.ReasoningEffort != "" { + reasoning := map[string]any{ + "enabled": true, + } + if request.ReasoningEffort != "none" { + reasoning["effort"] = request.ReasoningEffort + marshal, err := common.Marshal(reasoning) + if err != nil { + return nil, fmt.Errorf("error marshalling reasoning: %w", err) + } + request.Reasoning = marshal + } + } + } } } if strings.HasPrefix(request.Model, "o") || strings.HasPrefix(request.Model, "gpt-5") { diff --git a/relay/channel/openai/relay-openai.go b/relay/channel/openai/relay-openai.go index 9ae0a200..b8e72273 100644 --- a/relay/channel/openai/relay-openai.go +++ b/relay/channel/openai/relay-openai.go @@ -180,6 +180,9 @@ func OpenaiHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.Respo if err != nil { return nil, types.NewOpenAIError(err, types.ErrorCodeReadResponseBodyFailed, http.StatusInternalServerError) } + if common.DebugEnabled { + println("upstream response body:", string(responseBody)) + } err = common.Unmarshal(responseBody, &simpleResponse) if err != nil { return nil, types.NewOpenAIError(err, types.ErrorCodeBadResponseBody, http.StatusInternalServerError) diff --git a/service/convert.go b/service/convert.go index 967e4682..925feae9 100644 --- a/service/convert.go +++ b/service/convert.go @@ -401,22 +401,26 @@ func ResponseOpenAI2Claude(openAIResponse *dto.OpenAITextResponse, info *relayco } for _, choice := range openAIResponse.Choices { stopReason = stopReasonOpenAI2Claude(choice.FinishReason) - claudeContent := dto.ClaudeMediaMessage{} if choice.FinishReason == "tool_calls" { - claudeContent.Type = "tool_use" - claudeContent.Id = choice.Message.ToolCallId - claudeContent.Name = choice.Message.ParseToolCalls()[0].Function.Name - var mapParams map[string]interface{} - if err := json.Unmarshal([]byte(choice.Message.ParseToolCalls()[0].Function.Arguments), &mapParams); err == nil { - claudeContent.Input = mapParams - } else { - claudeContent.Input = choice.Message.ParseToolCalls()[0].Function.Arguments + for _, toolUse := range choice.Message.ParseToolCalls() { + claudeContent := dto.ClaudeMediaMessage{} + claudeContent.Type = "tool_use" + claudeContent.Id = toolUse.ID + claudeContent.Name = toolUse.Function.Name + var mapParams map[string]interface{} + if err := common.Unmarshal([]byte(toolUse.Function.Arguments), &mapParams); err == nil { + claudeContent.Input = mapParams + } else { + claudeContent.Input = toolUse.Function.Arguments + } + contents = append(contents, claudeContent) } } else { + claudeContent := dto.ClaudeMediaMessage{} claudeContent.Type = "text" claudeContent.SetText(choice.Message.StringContent()) + contents = append(contents, claudeContent) } - contents = append(contents, claudeContent) } claudeResponse.Content = contents claudeResponse.StopReason = stopReason