From b95142bbacbd3d4b3775393a5b0b2f2d12c2684c Mon Sep 17 00:00:00 2001 From: Sh1n3zZ Date: Thu, 6 Mar 2025 19:16:26 +0800 Subject: [PATCH 1/2] fix: adapting return format for openrouter think content (#793) --- dto/openai_request.go | 1 + dto/openai_response.go | 9 +++++++-- relay/channel/openai/relay-openai.go | 27 +++++++++++++++++---------- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/dto/openai_request.go b/dto/openai_request.go index 6f12a19e..812e14a5 100644 --- a/dto/openai_request.go +++ b/dto/openai_request.go @@ -99,6 +99,7 @@ type Message struct { Name *string `json:"name,omitempty"` Prefix *bool `json:"prefix,omitempty"` ReasoningContent string `json:"reasoning_content,omitempty"` + Reasoning string `json:"reasoning,omitempty"` ToolCalls json.RawMessage `json:"tool_calls,omitempty"` ToolCallId string `json:"tool_call_id,omitempty"` parsedContent []MediaContent diff --git a/dto/openai_response.go b/dto/openai_response.go index 56fac585..a1d728fe 100644 --- a/dto/openai_response.go +++ b/dto/openai_response.go @@ -64,6 +64,7 @@ type ChatCompletionsStreamResponseChoice struct { type ChatCompletionsStreamResponseChoiceDelta struct { Content *string `json:"content,omitempty"` ReasoningContent *string `json:"reasoning_content,omitempty"` + Reasoning *string `json:"reasoning,omitempty"` Role string `json:"role,omitempty"` ToolCalls []ToolCallResponse `json:"tool_calls,omitempty"` } @@ -80,14 +81,18 @@ func (c *ChatCompletionsStreamResponseChoiceDelta) GetContentString() string { } func (c *ChatCompletionsStreamResponseChoiceDelta) GetReasoningContent() string { - if c.ReasoningContent == nil { + if c.ReasoningContent == nil && c.Reasoning == nil { return "" } - return *c.ReasoningContent + if c.ReasoningContent != nil { + return *c.ReasoningContent + } + return *c.Reasoning } func (c *ChatCompletionsStreamResponseChoiceDelta) SetReasoningContent(s string) { c.ReasoningContent = &s + c.Reasoning = &s } type ToolCallResponse struct { diff --git a/relay/channel/openai/relay-openai.go b/relay/channel/openai/relay-openai.go index 0afe3f51..c51d948b 100644 --- a/relay/channel/openai/relay-openai.go +++ b/relay/channel/openai/relay-openai.go @@ -4,10 +4,6 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/bytedance/gopkg/util/gopool" - "github.com/gin-gonic/gin" - "github.com/gorilla/websocket" - "github.com/pkg/errors" "io" "math" "mime/multipart" @@ -21,6 +17,11 @@ import ( "one-api/service" "os" "strings" + + "github.com/bytedance/gopkg/util/gopool" + "github.com/gin-gonic/gin" + "github.com/gorilla/websocket" + "github.com/pkg/errors" ) func sendStreamData(c *gin.Context, info *relaycommon.RelayInfo, data string, forceFormat bool, thinkToContent bool) error { @@ -55,7 +56,8 @@ func sendStreamData(c *gin.Context, info *relaycommon.RelayInfo, data string, fo response := lastStreamResponse.Copy() for i := range response.Choices { response.Choices[i].Delta.SetContentString("\n") - response.Choices[i].Delta.SetReasoningContent("") + response.Choices[i].Delta.ReasoningContent = nil + response.Choices[i].Delta.Reasoning = nil } info.ThinkingContentInfo.IsFirstThinkingContent = false return helper.ObjectData(c, response) @@ -74,8 +76,9 @@ func sendStreamData(c *gin.Context, info *relaycommon.RelayInfo, data string, fo if len(choice.Delta.GetContentString()) > 0 && !info.ThinkingContentInfo.SendLastThinkingContent { response := lastStreamResponse.Copy() for j := range response.Choices { - response.Choices[j].Delta.SetContentString("\n\n\n") - response.Choices[j].Delta.SetReasoningContent("") + response.Choices[j].Delta.SetContentString("\n") + response.Choices[j].Delta.ReasoningContent = nil + response.Choices[j].Delta.Reasoning = nil } info.ThinkingContentInfo.SendLastThinkingContent = true helper.ObjectData(c, response) @@ -84,7 +87,8 @@ func sendStreamData(c *gin.Context, info *relaycommon.RelayInfo, data string, fo // Convert reasoning content to regular content if len(choice.Delta.GetReasoningContent()) > 0 { lastStreamResponse.Choices[i].Delta.SetContentString(choice.Delta.GetReasoningContent()) - lastStreamResponse.Choices[i].Delta.SetReasoningContent("") + lastStreamResponse.Choices[i].Delta.ReasoningContent = nil + lastStreamResponse.Choices[i].Delta.Reasoning = nil } } @@ -178,7 +182,10 @@ func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel //} for _, choice := range streamResponse.Choices { responseTextBuilder.WriteString(choice.Delta.GetContentString()) + + // handle both reasoning_content and reasoning responseTextBuilder.WriteString(choice.Delta.GetReasoningContent()) + if choice.Delta.ToolCalls != nil { if len(choice.Delta.ToolCalls) > toolCount { toolCount = len(choice.Delta.ToolCalls) @@ -199,7 +206,7 @@ func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel //} for _, choice := range streamResponse.Choices { responseTextBuilder.WriteString(choice.Delta.GetContentString()) - responseTextBuilder.WriteString(choice.Delta.GetReasoningContent()) + responseTextBuilder.WriteString(choice.Delta.GetReasoningContent()) // This will handle both reasoning_content and reasoning if choice.Delta.ToolCalls != nil { if len(choice.Delta.ToolCalls) > toolCount { toolCount = len(choice.Delta.ToolCalls) @@ -291,7 +298,7 @@ func OpenaiHandler(c *gin.Context, resp *http.Response, promptTokens int, model if simpleResponse.Usage.TotalTokens == 0 || (simpleResponse.Usage.PromptTokens == 0 && simpleResponse.Usage.CompletionTokens == 0) { completionTokens := 0 for _, choice := range simpleResponse.Choices { - ctkm, _ := service.CountTextToken(choice.Message.StringContent()+choice.Message.ReasoningContent, model) + ctkm, _ := service.CountTextToken(choice.Message.StringContent()+choice.Message.ReasoningContent+choice.Message.Reasoning, model) completionTokens += ctkm } simpleResponse.Usage = dto.Usage{ From 894dce7366f98bac58e39da24a3465305ebe7298 Mon Sep 17 00:00:00 2001 From: Sh1n3zZ Date: Thu, 6 Mar 2025 19:20:29 +0800 Subject: [PATCH 2/2] fix: possible incomplete return of the think field and incorrect occurrences of the `reasoning` field --- relay/channel/openai/relay-openai.go | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/relay/channel/openai/relay-openai.go b/relay/channel/openai/relay-openai.go index c51d948b..223ddd3d 100644 --- a/relay/channel/openai/relay-openai.go +++ b/relay/channel/openai/relay-openai.go @@ -43,10 +43,15 @@ func sendStreamData(c *gin.Context, info *relaycommon.RelayInfo, data string, fo } hasThinkingContent := false + hasContent := false + var thinkingContent strings.Builder for _, choice := range lastStreamResponse.Choices { if len(choice.Delta.GetReasoningContent()) > 0 { hasThinkingContent = true - break + thinkingContent.WriteString(choice.Delta.GetReasoningContent()) + } + if len(choice.Delta.GetContentString()) > 0 { + hasContent = true } } @@ -55,14 +60,13 @@ func sendStreamData(c *gin.Context, info *relaycommon.RelayInfo, data string, fo if hasThinkingContent { response := lastStreamResponse.Copy() for i := range response.Choices { - response.Choices[i].Delta.SetContentString("\n") + // send `think` tag with thinking content + response.Choices[i].Delta.SetContentString("\n" + thinkingContent.String()) response.Choices[i].Delta.ReasoningContent = nil response.Choices[i].Delta.Reasoning = nil } info.ThinkingContentInfo.IsFirstThinkingContent = false return helper.ObjectData(c, response) - } else { - return helper.ObjectData(c, lastStreamResponse) } } @@ -73,10 +77,10 @@ func sendStreamData(c *gin.Context, info *relaycommon.RelayInfo, data string, fo // Process each choice for i, choice := range lastStreamResponse.Choices { // Handle transition from thinking to content - if len(choice.Delta.GetContentString()) > 0 && !info.ThinkingContentInfo.SendLastThinkingContent { + if hasContent && !info.ThinkingContentInfo.SendLastThinkingContent { response := lastStreamResponse.Copy() for j := range response.Choices { - response.Choices[j].Delta.SetContentString("\n") + response.Choices[j].Delta.SetContentString("\n\n") response.Choices[j].Delta.ReasoningContent = nil response.Choices[j].Delta.Reasoning = nil } @@ -89,6 +93,10 @@ func sendStreamData(c *gin.Context, info *relaycommon.RelayInfo, data string, fo lastStreamResponse.Choices[i].Delta.SetContentString(choice.Delta.GetReasoningContent()) lastStreamResponse.Choices[i].Delta.ReasoningContent = nil lastStreamResponse.Choices[i].Delta.Reasoning = nil + } else if !hasThinkingContent && !hasContent { + // flush thinking content + lastStreamResponse.Choices[i].Delta.ReasoningContent = nil + lastStreamResponse.Choices[i].Delta.Reasoning = nil } }