From 5b264f3a5720ac8a409a192532f2445f77f6db73 Mon Sep 17 00:00:00 2001 From: Nekohy Date: Thu, 5 Mar 2026 06:12:48 +0800 Subject: [PATCH 1/2] feats: repair the thinking of claude to openrouter convert --- dto/claude.go | 14 ++++++++++++++ relay/channel/openai/adaptor.go | 1 + relay/channel/openrouter/dto.go | 1 + service/convert.go | 28 +++++++++++++++++++++------- 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/dto/claude.go b/dto/claude.go index e7d87c41f..73bfa9c54 100644 --- a/dto/claude.go +++ b/dto/claude.go @@ -218,6 +218,11 @@ type ClaudeRequest struct { ServiceTier string `json:"service_tier,omitempty"` } +// OutputConfigForEffort just for extract effort +type OutputConfigForEffort struct { + Effort string `json:"effort,omitempty"` +} + // createClaudeFileSource 根据数据内容创建正确类型的 FileSource func createClaudeFileSource(data string) *types.FileSource { if strings.HasPrefix(data, "http://") || strings.HasPrefix(data, "https://") { @@ -409,6 +414,15 @@ func (c *ClaudeRequest) GetTools() []any { } } +func (c *ClaudeRequest) GetEfforts() string { + var OutputConfig OutputConfigForEffort + if err := json.Unmarshal(c.OutputConfig, &OutputConfig); err == nil { + effort := OutputConfig.Effort + return effort + } + return "" +} + // ProcessTools 处理工具列表,支持类型断言 func ProcessTools(tools []any) ([]*Tool, []*ClaudeWebSearchTool) { var normalTools []*Tool diff --git a/relay/channel/openai/adaptor.go b/relay/channel/openai/adaptor.go index ed2c70c1e..59fadedac 100644 --- a/relay/channel/openai/adaptor.go +++ b/relay/channel/openai/adaptor.go @@ -298,6 +298,7 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn } reasoning := openrouter.RequestReasoning{ + Enabled: true, MaxTokens: *thinking.BudgetTokens, } diff --git a/relay/channel/openrouter/dto.go b/relay/channel/openrouter/dto.go index a32499852..73a1e445a 100644 --- a/relay/channel/openrouter/dto.go +++ b/relay/channel/openrouter/dto.go @@ -3,6 +3,7 @@ package openrouter import "encoding/json" type RequestReasoning struct { + Enabled bool `json:"enabled"` // One of the following (not both): Effort string `json:"effort,omitempty"` // Can be "high", "medium", or "low" (OpenAI-style) MaxTokens int `json:"max_tokens,omitempty"` // Specific token limit (Anthropic-style) diff --git a/service/convert.go b/service/convert.go index f249981b5..ad2854b44 100644 --- a/service/convert.go +++ b/service/convert.go @@ -34,16 +34,30 @@ func ClaudeToOpenAIRequest(claudeRequest dto.ClaudeRequest, info *relaycommon.Re isOpenRouter := info.ChannelType == constant.ChannelTypeOpenRouter - if claudeRequest.Thinking != nil && claudeRequest.Thinking.Type == "enabled" { + if claudeRequest.Thinking != nil && (claudeRequest.Thinking.Type == "enabled" || claudeRequest.Thinking.Type == "adaptive") { if isOpenRouter { - reasoning := openrouter.RequestReasoning{ - MaxTokens: claudeRequest.Thinking.GetBudgetTokens(), + if effort := claudeRequest.GetEfforts(); effort != "" { + effortBytes, _ := json.Marshal(effort) + openAIRequest.Verbosity = effortBytes } - reasoningJSON, err := json.Marshal(reasoning) - if err != nil { - return nil, fmt.Errorf("failed to marshal reasoning: %w", err) + if claudeRequest.Thinking != nil { + var reasoning openrouter.RequestReasoning + if claudeRequest.Thinking.Type == "enabled" { + reasoning = openrouter.RequestReasoning{ + Enabled: true, + MaxTokens: claudeRequest.Thinking.GetBudgetTokens(), + } + } else if claudeRequest.Thinking.Type == "adaptive" { + reasoning = openrouter.RequestReasoning{ + Enabled: true, + } + } + reasoningJSON, err := json.Marshal(reasoning) + if err != nil { + return nil, fmt.Errorf("failed to marshal reasoning: %w", err) + } + openAIRequest.Reasoning = reasoningJSON } - openAIRequest.Reasoning = reasoningJSON } else { thinkingSuffix := "-thinking" if strings.HasSuffix(info.OriginModelName, thinkingSuffix) && From de12d6df0560b167be00da533a8ee8209129db76 Mon Sep 17 00:00:00 2001 From: Nekohy Date: Thu, 5 Mar 2026 06:24:22 +0800 Subject: [PATCH 2/2] delete some if --- service/convert.go | 50 ++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/service/convert.go b/service/convert.go index ad2854b44..7efaba6cf 100644 --- a/service/convert.go +++ b/service/convert.go @@ -34,36 +34,34 @@ func ClaudeToOpenAIRequest(claudeRequest dto.ClaudeRequest, info *relaycommon.Re isOpenRouter := info.ChannelType == constant.ChannelTypeOpenRouter - if claudeRequest.Thinking != nil && (claudeRequest.Thinking.Type == "enabled" || claudeRequest.Thinking.Type == "adaptive") { - if isOpenRouter { - if effort := claudeRequest.GetEfforts(); effort != "" { - effortBytes, _ := json.Marshal(effort) - openAIRequest.Verbosity = effortBytes - } - if claudeRequest.Thinking != nil { - var reasoning openrouter.RequestReasoning - if claudeRequest.Thinking.Type == "enabled" { - reasoning = openrouter.RequestReasoning{ - Enabled: true, - MaxTokens: claudeRequest.Thinking.GetBudgetTokens(), - } - } else if claudeRequest.Thinking.Type == "adaptive" { - reasoning = openrouter.RequestReasoning{ - Enabled: true, - } + if isOpenRouter { + if effort := claudeRequest.GetEfforts(); effort != "" { + effortBytes, _ := json.Marshal(effort) + openAIRequest.Verbosity = effortBytes + } + if claudeRequest.Thinking != nil { + var reasoning openrouter.RequestReasoning + if claudeRequest.Thinking.Type == "enabled" { + reasoning = openrouter.RequestReasoning{ + Enabled: true, + MaxTokens: claudeRequest.Thinking.GetBudgetTokens(), } - reasoningJSON, err := json.Marshal(reasoning) - if err != nil { - return nil, fmt.Errorf("failed to marshal reasoning: %w", err) + } else if claudeRequest.Thinking.Type == "adaptive" { + reasoning = openrouter.RequestReasoning{ + Enabled: true, } - openAIRequest.Reasoning = reasoningJSON } - } else { - thinkingSuffix := "-thinking" - if strings.HasSuffix(info.OriginModelName, thinkingSuffix) && - !strings.HasSuffix(openAIRequest.Model, thinkingSuffix) { - openAIRequest.Model = openAIRequest.Model + thinkingSuffix + reasoningJSON, err := json.Marshal(reasoning) + if err != nil { + return nil, fmt.Errorf("failed to marshal reasoning: %w", err) } + openAIRequest.Reasoning = reasoningJSON + } + } else { + thinkingSuffix := "-thinking" + if strings.HasSuffix(info.OriginModelName, thinkingSuffix) && + !strings.HasSuffix(openAIRequest.Model, thinkingSuffix) { + openAIRequest.Model = openAIRequest.Model + thinkingSuffix } }