Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions constant/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,12 @@ var ChannelSpecialBases = map[string]ChannelSpecialBase{
ClaudeBaseURL: "https://ark.cn-beijing.volces.com/api/coding",
OpenAIBaseURL: "https://ark.cn-beijing.volces.com/api/coding/v3",
},
"ali-token-plan": {
ClaudeBaseURL: "https://token-plan.cn-beijing.maas.aliyuncs.com/apps/anthropic",
OpenAIBaseURL: "https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1",
},
"minimax-token-plan": {
ClaudeBaseURL: "https://api.minimaxi.com/anthropic",
OpenAIBaseURL: "https://api.minimaxi.com/v1",
},
}
12 changes: 12 additions & 0 deletions relay/channel/ali/adaptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"

"github.com/QuantumNous/new-api/common"
channelconstant "github.com/QuantumNous/new-api/constant"
"github.com/QuantumNous/new-api/dto"
"github.com/QuantumNous/new-api/relay/channel"
"github.com/QuantumNous/new-api/relay/channel/claude"
Expand Down Expand Up @@ -90,6 +91,17 @@ func (a *Adaptor) Init(info *relaycommon.RelayInfo) {

func (a *Adaptor) GetRequestURL(info *relaycommon.RelayInfo) (string, error) {
var fullRequestURL string

baseURL := info.ChannelBaseUrl
if specialPlan, ok := channelconstant.ChannelSpecialBases[baseURL]; ok {
switch info.RelayFormat {
case types.RelayFormatClaude:
return fmt.Sprintf("%s/v1/messages", specialPlan.ClaudeBaseURL), nil
default:
return fmt.Sprintf("%s/chat/completions", specialPlan.OpenAIBaseURL), nil
}
Comment on lines +96 to +102

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Special-plan early return can mismatch URL with request/response format paths.

Line 98-101 forces Claude requests to anthropic URL and all non-Claude to chat-completions. That conflicts with existing model-gated conversion/response logic (Line 75-87, Line 255-263) and bypasses relay-mode routes (embeddings/rerank/images/responses), causing invalid upstream calls for reachable paths.

Suggested direction
 baseURL := info.ChannelBaseUrl
 if specialPlan, ok := channelconstant.ChannelSpecialBases[baseURL]; ok {
 	switch info.RelayFormat {
 	case types.RelayFormatClaude:
-		return fmt.Sprintf("%s/v1/messages", specialPlan.ClaudeBaseURL), nil
+		if supportsAliAnthropicMessages(info.UpstreamModelName) {
+			return fmt.Sprintf("%s/v1/messages", specialPlan.ClaudeBaseURL), nil
+		}
+		// fallback to existing OpenAI-compatible routing path below
 	default:
-		return fmt.Sprintf("%s/chat/completions", specialPlan.OpenAIBaseURL), nil
+		// only short-circuit chat-completions; keep other relay modes on existing switch below
+		if info.RelayMode == constant.RelayModeCompletions || info.RelayMode == constant.RelayModeChatCompletions {
+			return fmt.Sprintf("%s/chat/completions", specialPlan.OpenAIBaseURL), nil
+		}
 	}
 }

Also ensure ConvertClaudeRequest/DoResponse use the same special-plan rule so URL, payload shape, and response parser stay consistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@relay/channel/ali/adaptor.go` around lines 96 - 102, The early-return in
adaptor.go that maps ChannelSpecialBases[baseURL] to either
specialPlan.ClaudeBaseURL for types.RelayFormatClaude or
specialPlan.OpenAIBaseURL for others can misroute requests and bypass relay-mode
paths; update the routing so it does not unconditionally pick Claude vs OpenAI
by RelayFormat alone but instead reuses the same special-plan resolution logic
used by ConvertClaudeRequest and DoResponse (so path, payload shape and response
parsing remain consistent), i.e., determine the intended upstream route based on
the request's intended mode (embedding/rerank/image/response) and the
model-gated conversion logic, then build the URL from specialPlan accordingly
rather than short-circuiting on info.RelayFormat.

}

switch info.RelayFormat {
case types.RelayFormatClaude:
if supportsAliAnthropicMessages(info.UpstreamModelName) {
Expand Down
12 changes: 11 additions & 1 deletion relay/channel/minimax/relay-minimax.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,19 @@ func GetRequestURL(info *relaycommon.RelayInfo) (string, error) {
if baseUrl == "" {
baseUrl = channelconstant.ChannelBaseURLs[channelconstant.ChannelTypeMiniMax]
}

if specialPlan, ok := channelconstant.ChannelSpecialBases[baseUrl]; ok {
switch info.RelayFormat {
case types.RelayFormatClaude:
return fmt.Sprintf("%s/v1/messages", specialPlan.ClaudeBaseURL), nil
default:
return fmt.Sprintf("%s/chat/completions", specialPlan.OpenAIBaseURL), nil
}
Comment on lines +18 to +24

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Special-plan path drops relay-mode routing for non-Claude requests.

At Line 23, all non-Claude traffic is forced to /chat/completions, so image/audio relay modes are misrouted when baseUrl is a special plan.

Suggested fix
 if specialPlan, ok := channelconstant.ChannelSpecialBases[baseUrl]; ok {
 	switch info.RelayFormat {
 	case types.RelayFormatClaude:
 		return fmt.Sprintf("%s/v1/messages", specialPlan.ClaudeBaseURL), nil
 	default:
-		return fmt.Sprintf("%s/chat/completions", specialPlan.OpenAIBaseURL), nil
+		switch info.RelayMode {
+		case constant.RelayModeChatCompletions:
+			return fmt.Sprintf("%s/chat/completions", specialPlan.OpenAIBaseURL), nil
+		default:
+			return "", fmt.Errorf("relay mode %d is not supported for special base %q", info.RelayMode, baseUrl)
+		}
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@relay/channel/minimax/relay-minimax.go` around lines 18 - 24, When a
specialPlan is found the code currently forces all non-Claude traffic to
specialPlan.OpenAIBaseURL + "/chat/completions", dropping relay-mode routing;
change the branch so that after handling RelayFormatClaude (using
specialPlan.ClaudeBaseURL + "/v1/messages") you select the OpenAI endpoint based
on the same relay-format/mode logic used for the normal (non-special) path, i.e.
use info.RelayFormat / any RelayMode fields to choose the correct path and then
return specialPlan.OpenAIBaseURL + that path instead of always
"/chat/completions" (inspect and reuse the routing logic applied elsewhere for
non-special bases).

}

switch info.RelayFormat {
case types.RelayFormatClaude:
return fmt.Sprintf("%s/anthropic/v1/messages", info.ChannelBaseUrl), nil
return fmt.Sprintf("%s/anthropic/v1/messages", baseUrl), nil
default:
switch info.RelayMode {
case constant.RelayModeChatCompletions:
Expand Down