From a4629f26309c3e98a0f2e1881467034b086180fe Mon Sep 17 00:00:00 2001 From: Nekohy Date: Thu, 5 Mar 2026 06:12:48 +0800 Subject: [PATCH] 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 e7d87c41..73bfa9c5 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 ed2c70c1..59fadeda 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 a3249985..73a1e445 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 f249981b..ad2854b4 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) &&