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
4 changes: 3 additions & 1 deletion common/api_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ func ChannelType2APIType(channelType int) (int, bool) {
apiType = constant.APITypeDeepSeek
case constant.ChannelTypeMokaAI:
apiType = constant.APITypeMokaAI
case constant.ChannelTypeVolcEngine:
case constant.ChannelTypeVolcEngine,
constant.ChannelTypeVolcEngineAgentPlan,
constant.ChannelTypeVolcEngineCodingPlan:
apiType = constant.APITypeVolcEngine
case constant.ChannelTypeBaiduV2:
apiType = constant.APITypeBaiduV2
Expand Down
6 changes: 6 additions & 0 deletions common/endpoint_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ func GetEndpointTypesByChannelType(channelType int, modelName string) []constant
endpointTypes = []constant.EndpointType{constant.EndpointTypeOpenAI}
case constant.ChannelTypeXai:
endpointTypes = []constant.EndpointType{constant.EndpointTypeOpenAI, constant.EndpointTypeOpenAIResponse}
case constant.ChannelTypeVolcEngineAgentPlan, constant.ChannelTypeVolcEngineCodingPlan:
endpointTypes = []constant.EndpointType{
constant.EndpointTypeOpenAIResponse,
constant.EndpointTypeAnthropic,
constant.EndpointTypeOpenAI,
}
case constant.ChannelTypeSora:
endpointTypes = []constant.EndpointType{constant.EndpointTypeOpenAIVideo}
case constant.ChannelTypeSub2API, constant.ChannelTypeNewAPI:
Expand Down
244 changes: 129 additions & 115 deletions constant/channel.go
Original file line number Diff line number Diff line change
@@ -1,64 +1,66 @@
package constant

const (
ChannelTypeUnknown = 0
ChannelTypeOpenAI = 1
ChannelTypeMidjourney = 2
ChannelTypeAzure = 3
ChannelTypeOllama = 4
ChannelTypeMidjourneyPlus = 5
ChannelTypeOpenAIMax = 6
ChannelTypeOhMyGPT = 7
ChannelTypeCustom = 8
ChannelTypeAILS = 9
ChannelTypeAIProxy = 10
ChannelTypePaLM = 11
ChannelTypeAPI2GPT = 12
ChannelTypeAIGC2D = 13
ChannelTypeAnthropic = 14
ChannelTypeBaidu = 15
ChannelTypeZhipu = 16
ChannelTypeAli = 17
ChannelTypeXunfei = 18
ChannelType360 = 19
ChannelTypeOpenRouter = 20
ChannelTypeAIProxyLibrary = 21
ChannelTypeFastGPT = 22
ChannelTypeTencent = 23
ChannelTypeGemini = 24
ChannelTypeMoonshot = 25
ChannelTypeZhipu_v4 = 26
ChannelTypePerplexity = 27
ChannelTypeLingYiWanWu = 31
ChannelTypeAws = 33
ChannelTypeCohere = 34
ChannelTypeMiniMax = 35
ChannelTypeSunoAPI = 36
ChannelTypeDify = 37
ChannelTypeJina = 38
ChannelCloudflare = 39
ChannelTypeSiliconFlow = 40
ChannelTypeVertexAi = 41
ChannelTypeMistral = 42
ChannelTypeDeepSeek = 43
ChannelTypeMokaAI = 44
ChannelTypeVolcEngine = 45
ChannelTypeBaiduV2 = 46
ChannelTypeXinference = 47
ChannelTypeXai = 48
ChannelTypeCoze = 49
ChannelTypeKling = 50
ChannelTypeJimeng = 51
ChannelTypeVidu = 52
ChannelTypeSubmodel = 53
ChannelTypeDoubaoVideo = 54
ChannelTypeSora = 55
ChannelTypeReplicate = 56
ChannelTypeCodex = 57
ChannelTypeAdvancedCustom = 58
ChannelTypeSub2API = 59
ChannelTypeNewAPI = 60
ChannelTypeDummy // this one is only for count, do not add any channel after this
ChannelTypeUnknown = 0
ChannelTypeOpenAI = 1
ChannelTypeMidjourney = 2
ChannelTypeAzure = 3
ChannelTypeOllama = 4
ChannelTypeMidjourneyPlus = 5
ChannelTypeOpenAIMax = 6
ChannelTypeOhMyGPT = 7
ChannelTypeCustom = 8
ChannelTypeAILS = 9
ChannelTypeAIProxy = 10
ChannelTypePaLM = 11
ChannelTypeAPI2GPT = 12
ChannelTypeAIGC2D = 13
ChannelTypeAnthropic = 14
ChannelTypeBaidu = 15
ChannelTypeZhipu = 16
ChannelTypeAli = 17
ChannelTypeXunfei = 18
ChannelType360 = 19
ChannelTypeOpenRouter = 20
ChannelTypeAIProxyLibrary = 21
ChannelTypeFastGPT = 22
ChannelTypeTencent = 23
ChannelTypeGemini = 24
ChannelTypeMoonshot = 25
ChannelTypeZhipu_v4 = 26
ChannelTypePerplexity = 27
ChannelTypeLingYiWanWu = 31
ChannelTypeAws = 33
ChannelTypeCohere = 34
ChannelTypeMiniMax = 35
ChannelTypeSunoAPI = 36
ChannelTypeDify = 37
ChannelTypeJina = 38
ChannelCloudflare = 39
ChannelTypeSiliconFlow = 40
ChannelTypeVertexAi = 41
ChannelTypeMistral = 42
ChannelTypeDeepSeek = 43
ChannelTypeMokaAI = 44
ChannelTypeVolcEngine = 45
ChannelTypeBaiduV2 = 46
ChannelTypeXinference = 47
ChannelTypeXai = 48
ChannelTypeCoze = 49
ChannelTypeKling = 50
ChannelTypeJimeng = 51
ChannelTypeVidu = 52
ChannelTypeSubmodel = 53
ChannelTypeDoubaoVideo = 54
ChannelTypeSora = 55
ChannelTypeReplicate = 56
ChannelTypeCodex = 57
ChannelTypeAdvancedCustom = 58
ChannelTypeSub2API = 59
ChannelTypeNewAPI = 60
ChannelTypeVolcEngineAgentPlan = 61
ChannelTypeVolcEngineCodingPlan = 62
ChannelTypeDummy // this one is only for count, do not add any channel after this
Comment on lines +61 to +63

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Find usages of ChannelTypeDummy to assess whether its aliasing with
# ChannelTypeVolcEngineCodingPlan has functional impact.
rg -n -C3 --type=go '\bChannelTypeDummy\b'

Repository: QuantumNous/new-api

Length of output: 157


🏁 Script executed:

#!/bin/bash
set -u

echo "== candidate files =="
fd -a 'channel\.go$' . || true

echo "== ChannelType constants =="
rg -n -C4 'ChannelType(VolcEngineAgentPlan|VolcEngineCodingPlan|Dummy|NewAPI)|type\s+Channel' . || true

echo "== all symbol references =="
rg -n -C2 '\bChannelTypeDummy\b|\bChannelTypeVolcEngineCodingPlan\b' . || true

echo "== const block excerpt =="
if [ -f constant/channel.go ]; then
  nl -ba constant/channel.go | sed -n '1,90p'
fi

echo "== programmatic const values for const block =="
python3 - <<'PY'
from pathlib import Path
p = Path('constant/channel.go')
if p.exists():
    lines = p.read_text().splitlines()
    in_block = False
    vals = {}
    for i,line in enumerate(lines,1):
        s=line.strip()
        if s.startswith('const ('):
            in_block=True
            continue
        if in_block and s == ')':
            break
        if in_block and '=' in s:
            name = s.split()[0]
            _, rest = s.split('=',1)
            vals[name]=rest.strip()
        elif in_block and s and not s.startswith('//') and not s.startswith('*'):
            vals[s.split()[0]]=vals[list(vals)[-1]][0] if vals else None
    for name in ['ChannelTypeVolcEngineAgentPlan','ChannelTypeVolcEngineCodingPlan','ChannelTypeDummy']:
        print(name, vals.get(name))
PY

Repository: QuantumNous/new-api

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -u

echo "== all ChannelTypeDummy references with grep =="
grep -RInwo '\bChannelTypeDummy\b' . || true

echo "== controller/model.go relevant loop =="
nl -ba controller/model.go | sed -n '70,110p'

echo "== constants surrounding ChannelType constants =="
nl -ba constant/channel.go | sed -n '44,66p'

Repository: QuantumNous/new-api

Length of output: 452


Replace the ChannelTypeDummy alias before using it as a count bound.

ChannelTypeDummy still inherits the previous const value, so it equals constant.ChannelTypeVolcEngineCodingPlan (62). Since controller/model.go iterates for i := 1; i <= constant.ChannelTypeDummy; i++, each route registration includes 62 twice. Give ChannelTypeDummy an unused sentinel value (for example, 63) so the loop count remains correct.

🤖 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 `@constant/channel.go` around lines 61 - 63, Update the ChannelTypeDummy
constant in the channel type declaration to an explicit unused sentinel value
after ChannelTypeVolcEngineCodingPlan, such as 63, so the controller/model.go
registration loop bounded by ChannelTypeDummy includes each channel exactly
once.


)

Expand Down Expand Up @@ -124,66 +126,70 @@ var ChannelBaseURLs = []string{
"", //58
"", //59
"", //60
"https://ark.cn-beijing.volces.com/api/plan", //61
"https://ark.cn-beijing.volces.com/api/coding", //62
}

var ChannelTypeNames = map[int]string{
ChannelTypeUnknown: "Unknown",
ChannelTypeOpenAI: "OpenAI",
ChannelTypeMidjourney: "Midjourney",
ChannelTypeAzure: "Azure",
ChannelTypeOllama: "Ollama",
ChannelTypeMidjourneyPlus: "MidjourneyPlus",
ChannelTypeOpenAIMax: "OpenAIMax",
ChannelTypeOhMyGPT: "OhMyGPT",
ChannelTypeCustom: "Custom",
ChannelTypeAILS: "AILS",
ChannelTypeAIProxy: "AIProxy",
ChannelTypePaLM: "PaLM",
ChannelTypeAPI2GPT: "API2GPT",
ChannelTypeAIGC2D: "AIGC2D",
ChannelTypeAnthropic: "Anthropic",
ChannelTypeBaidu: "Baidu",
ChannelTypeZhipu: "Zhipu",
ChannelTypeAli: "Ali",
ChannelTypeXunfei: "Xunfei",
ChannelType360: "360",
ChannelTypeOpenRouter: "OpenRouter",
ChannelTypeAIProxyLibrary: "AIProxyLibrary",
ChannelTypeFastGPT: "FastGPT",
ChannelTypeTencent: "Tencent",
ChannelTypeGemini: "Gemini",
ChannelTypeMoonshot: "Moonshot",
ChannelTypeZhipu_v4: "ZhipuV4",
ChannelTypePerplexity: "Perplexity",
ChannelTypeLingYiWanWu: "LingYiWanWu",
ChannelTypeAws: "AWS",
ChannelTypeCohere: "Cohere",
ChannelTypeMiniMax: "MiniMax",
ChannelTypeSunoAPI: "SunoAPI",
ChannelTypeDify: "Dify",
ChannelTypeJina: "Jina",
ChannelCloudflare: "Cloudflare",
ChannelTypeSiliconFlow: "SiliconFlow",
ChannelTypeVertexAi: "VertexAI",
ChannelTypeMistral: "Mistral",
ChannelTypeDeepSeek: "DeepSeek",
ChannelTypeMokaAI: "MokaAI",
ChannelTypeVolcEngine: "VolcEngine",
ChannelTypeBaiduV2: "BaiduV2",
ChannelTypeXinference: "Xinference",
ChannelTypeXai: "xAI",
ChannelTypeCoze: "Coze",
ChannelTypeKling: "Kling",
ChannelTypeJimeng: "Jimeng",
ChannelTypeVidu: "Vidu",
ChannelTypeSubmodel: "Submodel",
ChannelTypeDoubaoVideo: "DoubaoVideo",
ChannelTypeSora: "Sora",
ChannelTypeReplicate: "Replicate",
ChannelTypeCodex: "ChatGPT Subscription (Codex)",
ChannelTypeAdvancedCustom: "Advanced Custom",
ChannelTypeSub2API: "Sub2API",
ChannelTypeNewAPI: "New API",
ChannelTypeUnknown: "Unknown",
ChannelTypeOpenAI: "OpenAI",
ChannelTypeMidjourney: "Midjourney",
ChannelTypeAzure: "Azure",
ChannelTypeOllama: "Ollama",
ChannelTypeMidjourneyPlus: "MidjourneyPlus",
ChannelTypeOpenAIMax: "OpenAIMax",
ChannelTypeOhMyGPT: "OhMyGPT",
ChannelTypeCustom: "Custom",
ChannelTypeAILS: "AILS",
ChannelTypeAIProxy: "AIProxy",
ChannelTypePaLM: "PaLM",
ChannelTypeAPI2GPT: "API2GPT",
ChannelTypeAIGC2D: "AIGC2D",
ChannelTypeAnthropic: "Anthropic",
ChannelTypeBaidu: "Baidu",
ChannelTypeZhipu: "Zhipu",
ChannelTypeAli: "Ali",
ChannelTypeXunfei: "Xunfei",
ChannelType360: "360",
ChannelTypeOpenRouter: "OpenRouter",
ChannelTypeAIProxyLibrary: "AIProxyLibrary",
ChannelTypeFastGPT: "FastGPT",
ChannelTypeTencent: "Tencent",
ChannelTypeGemini: "Gemini",
ChannelTypeMoonshot: "Moonshot",
ChannelTypeZhipu_v4: "ZhipuV4",
ChannelTypePerplexity: "Perplexity",
ChannelTypeLingYiWanWu: "LingYiWanWu",
ChannelTypeAws: "AWS",
ChannelTypeCohere: "Cohere",
ChannelTypeMiniMax: "MiniMax",
ChannelTypeSunoAPI: "SunoAPI",
ChannelTypeDify: "Dify",
ChannelTypeJina: "Jina",
ChannelCloudflare: "Cloudflare",
ChannelTypeSiliconFlow: "SiliconFlow",
ChannelTypeVertexAi: "VertexAI",
ChannelTypeMistral: "Mistral",
ChannelTypeDeepSeek: "DeepSeek",
ChannelTypeMokaAI: "MokaAI",
ChannelTypeVolcEngine: "VolcEngine",
ChannelTypeBaiduV2: "BaiduV2",
ChannelTypeXinference: "Xinference",
ChannelTypeXai: "xAI",
ChannelTypeCoze: "Coze",
ChannelTypeKling: "Kling",
ChannelTypeJimeng: "Jimeng",
ChannelTypeVidu: "Vidu",
ChannelTypeSubmodel: "Submodel",
ChannelTypeDoubaoVideo: "DoubaoVideo",
ChannelTypeSora: "Sora",
ChannelTypeReplicate: "Replicate",
ChannelTypeCodex: "ChatGPT Subscription (Codex)",
ChannelTypeAdvancedCustom: "Advanced Custom",
ChannelTypeSub2API: "Sub2API",
ChannelTypeNewAPI: "New API",
ChannelTypeVolcEngineAgentPlan: "VolcEngine Agent Plan",
ChannelTypeVolcEngineCodingPlan: "VolcEngine Coding Plan",
}

func GetChannelTypeName(channelType int) string {
Expand Down Expand Up @@ -215,4 +221,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",
},
"https://ark.cn-beijing.volces.com/api/plan": {
ClaudeBaseURL: "https://ark.cn-beijing.volces.com/api/plan",
OpenAIBaseURL: "https://ark.cn-beijing.volces.com/api/plan/v3",
},
"https://ark.cn-beijing.volces.com/api/coding": {
ClaudeBaseURL: "https://ark.cn-beijing.volces.com/api/coding",
OpenAIBaseURL: "https://ark.cn-beijing.volces.com/api/coding/v3",
},
}
3 changes: 3 additions & 0 deletions constant/context_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ const (
ContextKeyChannelIsMultiKey ContextKey = "channel_is_multi_key"
ContextKeyChannelMultiKeyIndex ContextKey = "channel_multi_key_index"
ContextKeyChannelKey ContextKey = "channel_key"
// Sanitized upstream target persisted in admin-only log metadata.
ContextKeyUpstreamRequestURL ContextKey = "upstream_request_url"
ContextKeyUpstreamRequestMethod ContextKey = "upstream_request_method"

ContextKeyAutoGroup ContextKey = "auto_group"
ContextKeyAutoGroupIndex ContextKey = "auto_group_index"
Expand Down
9 changes: 7 additions & 2 deletions controller/channel-test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,13 @@ func normalizeChannelTestEndpoint(channel *model.Channel, modelName, endpointTyp
if strings.HasSuffix(modelName, ratio_setting.CompactModelSuffix) {
return string(constant.EndpointTypeOpenAIResponseCompact)
}
if channel != nil && channel.Type == constant.ChannelTypeCodex {
return string(constant.EndpointTypeOpenAIResponse)
if channel != nil {
switch channel.Type {
case constant.ChannelTypeCodex,
constant.ChannelTypeVolcEngineAgentPlan,
constant.ChannelTypeVolcEngineCodingPlan:
return string(constant.EndpointTypeOpenAIResponse)
}
}
return normalized
}
Expand Down
24 changes: 16 additions & 8 deletions controller/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ func FetchUpstreamModels(c *gin.Context) {
return
}

ids, err := fetchChannelUpstreamModelIDs(channel)
discovery, err := fetchChannelUpstreamModelDiscovery(channel)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"success": false,
Expand All @@ -249,11 +249,15 @@ func FetchUpstreamModels(c *gin.Context) {
return
}

c.JSON(http.StatusOK, gin.H{
response := gin.H{
"success": true,
"message": "",
"data": ids,
})
"data": discovery.Models,
}
if len(discovery.ModelMapping) > 0 {
response["model_mapping"] = discovery.ModelMapping
}
c.JSON(http.StatusOK, response)
}

func FixChannelsAbilities(c *gin.Context) {
Expand Down Expand Up @@ -1313,19 +1317,23 @@ func FetchModels(c *gin.Context) {
}
}

models, err := fetchChannelUpstreamModelIDs(channel)
discovery, err := fetchChannelUpstreamModelDiscovery(channel)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": fmt.Sprintf("获取模型列表失败: %s", err.Error()),
})
return
}
c.JSON(http.StatusOK, gin.H{
response := gin.H{
"success": true,
"message": "",
"data": models,
})
"data": discovery.Models,
}
if len(discovery.ModelMapping) > 0 {
response["model_mapping"] = discovery.ModelMapping
}
c.JSON(http.StatusOK, response)
}

func BatchSetChannelTag(c *gin.Context) {
Expand Down
Loading
Loading