From 8a951ce49e4c8be51e76641b89ec82ff09f8abd9 Mon Sep 17 00:00:00 2001 From: KaiShaoCheng Date: Fri, 5 Jun 2026 17:48:46 +0800 Subject: [PATCH] feat: add AGIone channel --- common/api_type.go | 2 + constant/api_type.go | 1 + constant/channel.go | 3 ++ controller/channel_upstream_update.go | 2 + relay/channel/agione/adaptor.go | 43 +++++++++++++++++++ relay/channel/agione/adaptor_test.go | 28 ++++++++++++ relay/channel/agione/constant.go | 9 ++++ relay/common/relay_info.go | 1 + relay/relay_adaptor.go | 3 ++ .../src/constants/channel.constants.js | 7 ++- .../src/features/channels/constants.ts | 4 +- .../channels/lib/channel-type-config.ts | 12 ++++++ 12 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 relay/channel/agione/adaptor.go create mode 100644 relay/channel/agione/adaptor_test.go create mode 100644 relay/channel/agione/constant.go diff --git a/common/api_type.go b/common/api_type.go index 39c1fe9a5406..f3b20bbddfb5 100644 --- a/common/api_type.go +++ b/common/api_type.go @@ -75,6 +75,8 @@ func ChannelType2APIType(channelType int) (int, bool) { apiType = constant.APITypeReplicate case constant.ChannelTypeCodex: apiType = constant.APITypeCodex + case constant.ChannelTypeAGIone: + apiType = constant.APITypeAGIone } if apiType == -1 { return constant.APITypeOpenAI, false diff --git a/constant/api_type.go b/constant/api_type.go index 536ebd2c7198..3a936ddc3d3a 100644 --- a/constant/api_type.go +++ b/constant/api_type.go @@ -36,5 +36,6 @@ const ( APITypeMiniMax APITypeReplicate APITypeCodex + APITypeAGIone APITypeDummy // this one is only for count, do not add any channel after this ) diff --git a/constant/channel.go b/constant/channel.go index 48502bedc52c..d6d05a7249da 100644 --- a/constant/channel.go +++ b/constant/channel.go @@ -55,6 +55,7 @@ const ( ChannelTypeSora = 55 ChannelTypeReplicate = 56 ChannelTypeCodex = 57 + ChannelTypeAGIone = 58 ChannelTypeDummy // this one is only for count, do not add any channel after this ) @@ -118,6 +119,7 @@ var ChannelBaseURLs = []string{ "https://api.openai.com", //55 "https://api.replicate.com", //56 "https://chatgpt.com", //57 + "https://agione.pro/hyperone/xapi/api/v1", //58 } var ChannelTypeNames = map[int]string{ @@ -175,6 +177,7 @@ var ChannelTypeNames = map[int]string{ ChannelTypeSora: "Sora", ChannelTypeReplicate: "Replicate", ChannelTypeCodex: "Codex", + ChannelTypeAGIone: "AGIone", } func GetChannelTypeName(channelType int) string { diff --git a/controller/channel_upstream_update.go b/controller/channel_upstream_update.go index 77a1e3c817a8..912abe8067df 100644 --- a/controller/channel_upstream_update.go +++ b/controller/channel_upstream_update.go @@ -311,6 +311,8 @@ func fetchChannelUpstreamModelIDs(channel *model.Channel) ([]string, error) { } else { url = fmt.Sprintf("%s/v1/models", baseURL) } + case constant.ChannelTypeAGIone: + url = fmt.Sprintf("%s/models", strings.TrimSuffix(baseURL, "/v1")) default: url = fmt.Sprintf("%s/v1/models", baseURL) } diff --git a/relay/channel/agione/adaptor.go b/relay/channel/agione/adaptor.go new file mode 100644 index 000000000000..2b830c078e94 --- /dev/null +++ b/relay/channel/agione/adaptor.go @@ -0,0 +1,43 @@ +package agione + +import ( + "fmt" + "strings" + + channelconstant "github.com/QuantumNous/new-api/constant" + "github.com/QuantumNous/new-api/relay/channel/openai" + relaycommon "github.com/QuantumNous/new-api/relay/common" + relayconstant "github.com/QuantumNous/new-api/relay/constant" + "github.com/QuantumNous/new-api/types" +) + +type Adaptor struct { + openai.Adaptor +} + +func (a *Adaptor) GetRequestURL(info *relaycommon.RelayInfo) (string, error) { + baseURL := info.ChannelBaseUrl + if baseURL == "" { + baseURL = channelconstant.ChannelBaseURLs[channelconstant.ChannelTypeAGIone] + } + + if (info.RelayFormat == types.RelayFormatClaude || info.RelayFormat == types.RelayFormatGemini) && + info.RelayMode != relayconstant.RelayModeResponses && + info.RelayMode != relayconstant.RelayModeResponsesCompact { + return fmt.Sprintf("%s/chat/completions", baseURL), nil + } + + requestPath := info.RequestURLPath + if requestPath == "" { + return baseURL, nil + } + return fmt.Sprintf("%s%s", baseURL, strings.TrimPrefix(requestPath, "/v1")), nil +} + +func (a *Adaptor) GetModelList() []string { + return ModelList +} + +func (a *Adaptor) GetChannelName() string { + return ChannelName +} diff --git a/relay/channel/agione/adaptor_test.go b/relay/channel/agione/adaptor_test.go new file mode 100644 index 000000000000..060c7c775996 --- /dev/null +++ b/relay/channel/agione/adaptor_test.go @@ -0,0 +1,28 @@ +package agione + +import ( + "testing" + + channelconstant "github.com/QuantumNous/new-api/constant" + relaycommon "github.com/QuantumNous/new-api/relay/common" +) + +func TestGetRequestURLTrimsOpenAIVersionPrefix(t *testing.T) { + adaptor := &Adaptor{} + info := &relaycommon.RelayInfo{ + ChannelMeta: &relaycommon.ChannelMeta{ + ChannelType: channelconstant.ChannelTypeAGIone, + ChannelBaseUrl: channelconstant.ChannelBaseURLs[channelconstant.ChannelTypeAGIone], + }, + RequestURLPath: "/v1/chat/completions", + } + + got, err := adaptor.GetRequestURL(info) + if err != nil { + t.Fatalf("GetRequestURL returned error: %v", err) + } + want := "https://agione.pro/hyperone/xapi/api/v1/chat/completions" + if got != want { + t.Fatalf("GetRequestURL() = %q, want %q", got, want) + } +} diff --git a/relay/channel/agione/constant.go b/relay/channel/agione/constant.go new file mode 100644 index 000000000000..1e441db0b892 --- /dev/null +++ b/relay/channel/agione/constant.go @@ -0,0 +1,9 @@ +package agione + +var ModelList = []string{ + "openai/GPT-5.5/c6fbe", + "anthropic/Claude-opus-4.7/a4d5d", + "deepseek/deepseek-v3.2/0000n", +} + +var ChannelName = "agione" diff --git a/relay/common/relay_info.go b/relay/common/relay_info.go index 2f7afd398599..430ba122eae2 100644 --- a/relay/common/relay_info.go +++ b/relay/common/relay_info.go @@ -336,6 +336,7 @@ var streamSupportedChannels = map[int]bool{ constant.ChannelTypeMoonshot: true, constant.ChannelTypeMiniMax: true, constant.ChannelTypeSiliconFlow: true, + constant.ChannelTypeAGIone: true, } func GenRelayInfoWs(c *gin.Context, ws *websocket.Conn) *RelayInfo { diff --git a/relay/relay_adaptor.go b/relay/relay_adaptor.go index 3139c9a2dd4a..d0a6c9087173 100644 --- a/relay/relay_adaptor.go +++ b/relay/relay_adaptor.go @@ -5,6 +5,7 @@ import ( "github.com/QuantumNous/new-api/constant" "github.com/QuantumNous/new-api/relay/channel" + "github.com/QuantumNous/new-api/relay/channel/agione" "github.com/QuantumNous/new-api/relay/channel/ali" "github.com/QuantumNous/new-api/relay/channel/aws" "github.com/QuantumNous/new-api/relay/channel/baidu" @@ -120,6 +121,8 @@ func GetAdaptor(apiType int) channel.Adaptor { return &replicate.Adaptor{} case constant.APITypeCodex: return &codex.Adaptor{} + case constant.APITypeAGIone: + return &agione.Adaptor{} } return nil } diff --git a/web/classic/src/constants/channel.constants.js b/web/classic/src/constants/channel.constants.js index 9fa78779de8f..fd9aa93a79f3 100644 --- a/web/classic/src/constants/channel.constants.js +++ b/web/classic/src/constants/channel.constants.js @@ -189,11 +189,16 @@ export const CHANNEL_OPTIONS = [ color: 'blue', label: 'Codex (OpenAI OAuth)', }, + { + value: 58, + color: 'green', + label: 'AGIone', + }, ]; // Channel types that support upstream model list fetching in UI. export const MODEL_FETCHABLE_CHANNEL_TYPES = new Set([ - 1, 4, 14, 34, 17, 26, 27, 24, 47, 25, 20, 23, 31, 40, 42, 48, 43, + 1, 4, 14, 34, 17, 26, 27, 24, 47, 25, 20, 23, 31, 40, 42, 48, 43, 58, ]); export const MODEL_TABLE_PAGE_SIZE = 10; diff --git a/web/default/src/features/channels/constants.ts b/web/default/src/features/channels/constants.ts index 5fd88d554820..fdc33444e238 100644 --- a/web/default/src/features/channels/constants.ts +++ b/web/default/src/features/channels/constants.ts @@ -76,11 +76,12 @@ export const CHANNEL_TYPES = { 55: 'Sora', 56: 'Replicate', 57: 'Codex', + 58: 'AGIone', } as const const CHANNEL_TYPE_DISPLAY_ORDER: number[] = [ 1, 14, 33, 24, 43, 3, 41, 48, 42, 34, 20, 4, 40, 27, 25, 17, 26, 15, 46, 23, - 18, 45, 31, 35, 49, 19, 47, 37, 38, 39, 11, 8, 57, 22, 21, 44, 2, 5, 36, 50, + 18, 45, 31, 35, 49, 19, 47, 37, 38, 39, 11, 58, 8, 57, 22, 21, 44, 2, 5, 36, 50, 51, 52, 53, 54, 55, 56, ] @@ -377,6 +378,7 @@ export const FIELD_DESCRIPTIONS = { export const MODEL_FETCHABLE_TYPES = new Set([ 1, 4, 14, 17, 20, 23, 24, 25, 26, 27, 31, 34, 35, 40, 42, 43, 47, 48, + 58, ]) export const TYPE_TO_KEY_PROMPT: Record = { diff --git a/web/default/src/features/channels/lib/channel-type-config.ts b/web/default/src/features/channels/lib/channel-type-config.ts index 097f942f81ab..bbb17ea05ebd 100644 --- a/web/default/src/features/channels/lib/channel-type-config.ts +++ b/web/default/src/features/channels/lib/channel-type-config.ts @@ -123,6 +123,18 @@ export const CHANNEL_TYPE_CONFIGS: Record = { models: 'Use model IDs from OpenRouter', }, }, + 58: { + id: 58, + name: CHANNEL_TYPES[58], + icon: 'openai', + defaultBaseUrl: 'https://agione.pro/hyperone/xapi/api/v1', + hints: { + key: 'AGIone Auth Token', + models: + 'openai/GPT-5.5/c6fbe,anthropic/Claude-opus-4.7/a4d5d,deepseek/deepseek-v3.2/0000n', + baseUrl: 'Default: https://agione.pro/hyperone/xapi/api/v1', + }, + }, 56: { id: 56, name: CHANNEL_TYPES[56],