feats: repair the thinking of claude to openrouter convert

This commit is contained in:
Nekohy
2026-03-05 06:12:48 +08:00
parent 887a929d65
commit 5b264f3a57
4 changed files with 37 additions and 7 deletions

View File

@@ -218,6 +218,11 @@ type ClaudeRequest struct {
ServiceTier string `json:"service_tier,omitempty"` ServiceTier string `json:"service_tier,omitempty"`
} }
// OutputConfigForEffort just for extract effort
type OutputConfigForEffort struct {
Effort string `json:"effort,omitempty"`
}
// createClaudeFileSource 根据数据内容创建正确类型的 FileSource // createClaudeFileSource 根据数据内容创建正确类型的 FileSource
func createClaudeFileSource(data string) *types.FileSource { func createClaudeFileSource(data string) *types.FileSource {
if strings.HasPrefix(data, "http://") || strings.HasPrefix(data, "https://") { 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 处理工具列表,支持类型断言 // ProcessTools 处理工具列表,支持类型断言
func ProcessTools(tools []any) ([]*Tool, []*ClaudeWebSearchTool) { func ProcessTools(tools []any) ([]*Tool, []*ClaudeWebSearchTool) {
var normalTools []*Tool var normalTools []*Tool

View File

@@ -298,6 +298,7 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn
} }
reasoning := openrouter.RequestReasoning{ reasoning := openrouter.RequestReasoning{
Enabled: true,
MaxTokens: *thinking.BudgetTokens, MaxTokens: *thinking.BudgetTokens,
} }

View File

@@ -3,6 +3,7 @@ package openrouter
import "encoding/json" import "encoding/json"
type RequestReasoning struct { type RequestReasoning struct {
Enabled bool `json:"enabled"`
// One of the following (not both): // One of the following (not both):
Effort string `json:"effort,omitempty"` // Can be "high", "medium", or "low" (OpenAI-style) Effort string `json:"effort,omitempty"` // Can be "high", "medium", or "low" (OpenAI-style)
MaxTokens int `json:"max_tokens,omitempty"` // Specific token limit (Anthropic-style) MaxTokens int `json:"max_tokens,omitempty"` // Specific token limit (Anthropic-style)

View File

@@ -34,16 +34,30 @@ func ClaudeToOpenAIRequest(claudeRequest dto.ClaudeRequest, info *relaycommon.Re
isOpenRouter := info.ChannelType == constant.ChannelTypeOpenRouter 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 { if isOpenRouter {
reasoning := openrouter.RequestReasoning{ if effort := claudeRequest.GetEfforts(); effort != "" {
MaxTokens: claudeRequest.Thinking.GetBudgetTokens(), effortBytes, _ := json.Marshal(effort)
openAIRequest.Verbosity = effortBytes
} }
reasoningJSON, err := json.Marshal(reasoning) if claudeRequest.Thinking != nil {
if err != nil { var reasoning openrouter.RequestReasoning
return nil, fmt.Errorf("failed to marshal reasoning: %w", err) 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 { } else {
thinkingSuffix := "-thinking" thinkingSuffix := "-thinking"
if strings.HasSuffix(info.OriginModelName, thinkingSuffix) && if strings.HasSuffix(info.OriginModelName, thinkingSuffix) &&