feat: publish sanitized custom.97 source

This commit is contained in:
cneicy committed 2026-10-27 20:43:39 +08:00
1 parent 8e6ed0317b
commit 86c0276156
1022 files changed
+69903 -19207

No files matched your search

+261 -4
View File
@@ -2,6 +2,7 @@ package plugins
import (
"io/fs"
"strings"
"testing"
"github.com/QuantumNous/new-api/common"
@@ -10,7 +11,7 @@ import (
"github.com/stretchr/testify/require"
)
var expectedKeys = []string{"alibaba", "doubao", "google", "hailuo", "jimeng", "kling", "sora", "sunoapi", "vertex-ai", "vidu"}
var expectedKeys = []string{"alibaba", "doubao", "google", "hailuo", "jimeng", "kling", "sora", "sunoapi", "vertex-ai", "vidu", "xai"}
func TestBuiltInVendorPluginsDeclareNativeRoutesAndLegacyChannelTypes(t *testing.T) {
generation := jsplugin.DefaultRegistry.Generation()
@@ -34,6 +35,23 @@ func TestBuiltInVendorPluginsDeclareNativeRoutesAndLegacyChannelTypes(t *testing
{"GET", "/suno/fetch/:task_id", "sunoapi", jsplugin.RouteTypeQuery, "", "renderTask"},
{"POST", "/doubao/api/v3/contents/generations/tasks", "doubao", jsplugin.RouteTypeSubmit, "", "taskCreated"},
{"GET", "/doubao/api/v3/contents/generations/tasks/:task_id", "doubao", jsplugin.RouteTypeQuery, "", "taskStatus"},
{"POST", "/doubao/api/v3/images/generations", "doubao", jsplugin.RouteTypeSubmit, "", "imageCreated"},
{"POST", "/xai/v1/videos/generations", "xai", jsplugin.RouteTypeSubmit, "", "videoCreated"},
{"POST", "/xai/v1/videos/edits", "xai", jsplugin.RouteTypeSubmit, "", "videoCreated"},
{"POST", "/xai/v1/videos/extensions", "xai", jsplugin.RouteTypeSubmit, "", "videoCreated"},
{"GET", "/xai/v1/videos/:request_id", "xai", jsplugin.RouteTypeQuery, "", "videoStatus"},
{"POST", "/hailuo/v1/video_generation", "hailuo", jsplugin.RouteTypeSubmit, "", "taskCreated"},
{"GET", "/hailuo/v1/query/video_generation/:task_id", "hailuo", jsplugin.RouteTypeQuery, "", "taskStatus"},
{"POST", "/hailuo/v2/video_generation", "hailuo", jsplugin.RouteTypeSubmit, "", "taskCreated"},
{"GET", "/hailuo/v2/query/video_generation/:task_id", "hailuo", jsplugin.RouteTypeQuery, "", "h3TaskStatus"},
{"POST", "/vidu/ent/v2/text2video", "vidu", jsplugin.RouteTypeSubmit, "", "taskCreated"},
{"POST", "/vidu/ent/v2/img2video", "vidu", jsplugin.RouteTypeSubmit, "", "taskCreated"},
{"POST", "/vidu/ent/v2/start-end2video", "vidu", jsplugin.RouteTypeSubmit, "", "taskCreated"},
{"POST", "/vidu/ent/v2/reference2video", "vidu", jsplugin.RouteTypeSubmit, "", "taskCreated"},
{"GET", "/vidu/ent/v2/tasks/:task_id/creations", "vidu", jsplugin.RouteTypeQuery, "", "taskStatus"},
{"POST", "/google/v1beta/models/:model", "google", jsplugin.RouteTypeSubmit, "", "operation"},
{"GET", "/google/v1beta/models/:model/operations/:task_id", "google", jsplugin.RouteTypeQuery, "", "operation"},
{"POST", "/vertex-ai/v1/projects/:project/locations/:location/publishers/google/models/:model", "vertex-ai", jsplugin.RouteTypeDynamic, "", "operation"},
}
for _, expected := range routes {
t.Run(expected.method+" "+expected.path, func(t *testing.T) {
@@ -46,6 +64,13 @@ func TestBuiltInVendorPluginsDeclareNativeRoutesAndLegacyChannelTypes(t *testing
})
}
// The legacy Wan edit route serves both the wan2.5 image-list body and the
// wanx2.1-imageedit function API.
imageEdit, found := generation.LookupDeclaredRoute("POST", "/ali/api/v1/services/aigc/image2image/image-synthesis")
require.True(t, found)
assert.Equal(t, "alibaba", imageEdit.Plugin.Meta.Key)
assert.ElementsMatch(t, []string{"wan2.5-i2i-preview", "wanx2.1-imageedit"}, imageEdit.Route.Models)
channelTypes := []struct {
value int
key string
@@ -57,6 +82,7 @@ func TestBuiltInVendorPluginsDeclareNativeRoutesAndLegacyChannelTypes(t *testing
{51, "jimeng"},
{54, "doubao"},
{55, "sora"},
{48, "xai"},
}
for _, channelType := range channelTypes {
plugin, found := generation.GetByChannelType(channelType.value)
@@ -112,9 +138,7 @@ func TestBuiltInTaskPluginResponsesAndUsageContracts(t *testing.T) {
assert.True(t, callable, hook)
}
for _, hook := range []string{"extractUsage", "extractUsageOnComplete"} {
callable, callableErr := plugin.Engine.HasExport(t.Context(), hook)
require.NoError(t, callableErr)
assert.True(t, callable, hook)
assert.True(t, plugin.Engine.HasExport(hook), hook)
}
require.NotEmpty(t, plugin.Meta.UsageSchema)
for usageKey, schema := range plugin.Meta.UsageSchema {
@@ -155,3 +179,236 @@ func TestBuiltInResponsesDecodersEchoChannelMappedAlias(t *testing.T) {
})
}
}
func TestBuiltInPluginsAddressNewAPIUpstreamOnNativeRoutes(t *testing.T) {
generation := jsplugin.DefaultRegistry.Generation()
require.NotNil(t, generation)
const base = "https://upstream.example"
cases := []struct {
key string
driver map[string]any
vendorKey string
vendorAuthPrefix string
vendorSubmit string
gatewaySubmit string
vendorQuery string
gatewayQuery string
content string
legacyKeyHeuristic bool
}{
{
key: "doubao",
driver: map[string]any{"action": "text_to_video", "model": "doubao-seedance-1-0-pro-250528", "upstreamModel": "doubao-seedance-1-0-pro-250528", "requestBody": map[string]any{"model": "doubao-seedance-1-0-pro-250528", "prompt": "a cat"}},
vendorKey: "vendor-key",
vendorAuthPrefix: "Bearer vendor-key",
vendorSubmit: "/api/v3/contents/generations/tasks",
gatewaySubmit: "/doubao/api/v3/contents/generations/tasks",
vendorQuery: "/api/v3/contents/generations/tasks/tid",
gatewayQuery: "/doubao/api/v3/contents/generations/tasks/tid",
},
{
key: "alibaba",
driver: map[string]any{"action": "text_to_video", "model": "wan2.2-t2v-plus", "upstreamModel": "wan2.2-t2v-plus", "requestBody": map[string]any{"model": "wan2.2-t2v-plus", "prompt": "a cat"}},
vendorKey: "vendor-key",
vendorAuthPrefix: "Bearer vendor-key",
vendorSubmit: "/api/v1/services/aigc/video-generation/video-synthesis",
gatewaySubmit: "/ali/api/v1/services/aigc/video-generation/video-synthesis",
vendorQuery: "/api/v1/tasks/tid",
gatewayQuery: "/ali/api/v1/tasks/tid",
},
{
key: "kling",
driver: map[string]any{"action": "text_to_video", "model": "kling-v1", "upstreamModel": "kling-v1", "requestBody": map[string]any{"prompt": "a cat"}},
vendorKey: "ak|sk",
vendorAuthPrefix: "Bearer ey",
vendorSubmit: "/v1/videos/text2video",
gatewaySubmit: "/kling/v1/videos/text2video",
vendorQuery: "/v1/videos/text2video/tid",
gatewayQuery: "/kling/v1/videos/text2video/tid",
legacyKeyHeuristic: true,
},
{
key: "jimeng",
driver: map[string]any{"action": "text_to_video", "model": "jimeng_vgfm_t2v_l20", "upstreamModel": "jimeng_vgfm_t2v_l20", "requestBody": map[string]any{"prompt": "a cat"}},
vendorKey: "ak|sk",
vendorAuthPrefix: "HMAC-SHA256",
vendorSubmit: "/?Action=CVSync2AsyncSubmitTask&Version=2022-08-31",
gatewaySubmit: "/jimeng/?Action=CVSync2AsyncSubmitTask&Version=2022-08-31",
vendorQuery: "/?Action=CVSync2AsyncGetResult&Version=2022-08-31",
gatewayQuery: "/jimeng/?Action=CVSync2AsyncGetResult&Version=2022-08-31",
legacyKeyHeuristic: true,
},
{
key: "sunoapi",
driver: map[string]any{"action": "MUSIC", "model": "suno_music", "upstreamModel": "suno_music", "requestBody": map[string]any{"prompt": "a song"}},
vendorKey: "vendor-key",
vendorAuthPrefix: "Bearer vendor-key",
vendorSubmit: "/suno/submit/MUSIC",
gatewaySubmit: "/suno/submit/MUSIC",
vendorQuery: "/suno/fetch",
gatewayQuery: "/suno/fetch",
},
{
key: "sora",
driver: map[string]any{"action": "text_to_video", "model": "sora-2", "upstreamModel": "sora-2", "requestBody": map[string]any{"prompt": "a cat"}},
vendorKey: "vendor-key",
vendorAuthPrefix: "Bearer vendor-key",
vendorSubmit: "/v1/videos",
gatewaySubmit: "/v1/videos",
vendorQuery: "/v1/videos/tid",
gatewayQuery: "/v1/videos/tid",
content: "/v1/videos/tid/content",
},
{
key: "xai",
driver: map[string]any{"action": "text_to_video", "model": "grok-imagine-video", "upstreamModel": "grok-imagine-video", "requestBody": map[string]any{"model": "grok-imagine-video", "prompt": "a cat"}},
vendorKey: "vendor-key",
vendorAuthPrefix: "Bearer vendor-key",
vendorSubmit: "/v1/videos/generations",
gatewaySubmit: "/xai/v1/videos/generations",
vendorQuery: "/v1/videos/tid",
gatewayQuery: "/xai/v1/videos/tid",
},
{
key: "hailuo",
driver: map[string]any{"action": "text_to_video", "model": "MiniMax-Hailuo-2.3", "upstreamModel": "MiniMax-Hailuo-2.3", "requestBody": map[string]any{"model": "MiniMax-Hailuo-2.3", "prompt": "a cat"}},
vendorKey: "vendor-key",
vendorAuthPrefix: "Bearer vendor-key",
vendorSubmit: "/v1/video_generation",
gatewaySubmit: "/hailuo/v1/video_generation",
vendorQuery: "/v1/query/video_generation?task_id=tid",
gatewayQuery: "/hailuo/v1/query/video_generation/tid",
},
{
key: "vidu",
driver: map[string]any{"action": "text_to_video", "model": "viduq2", "upstreamModel": "viduq2", "requestBody": map[string]any{"model": "viduq2", "prompt": "a cat"}},
vendorKey: "vendor-key",
vendorAuthPrefix: "Token vendor-key",
vendorSubmit: "/ent/v2/text2video",
gatewaySubmit: "/vidu/ent/v2/text2video",
vendorQuery: "/ent/v2/tasks/tid/creations",
gatewayQuery: "/vidu/ent/v2/tasks/tid/creations",
},
}
variants := []struct {
name string
upstream map[string]any
gateway bool
legacyKey bool
}{
{"vendor signal", map[string]any{"kind": "vendor"}, false, false},
{"no signal from an older host", nil, false, false},
{"new_api signal", map[string]any{"kind": "new_api"}, true, false},
{"legacy sk- key without a signal", nil, true, true},
}
for _, tc := range cases {
t.Run(tc.key, func(t *testing.T) {
plugin, found := generation.Get(tc.key)
require.True(t, found)
require.True(t, plugin.Meta.SupportsUpstream(jsplugin.UpstreamKindNewAPI), "%s must declare new_api to be bindable to a New API channel", tc.key)
call := func(hook string, args ...any) map[string]any {
value, err := plugin.Engine.Call(t.Context(), hook, args...)
require.NoError(t, err, hook)
encoded, err := common.Marshal(value)
require.NoError(t, err)
var descriptor map[string]any
require.NoError(t, common.Unmarshal(encoded, &descriptor))
return descriptor
}
for _, variant := range variants {
if variant.legacyKey && !tc.legacyKeyHeuristic {
continue
}
t.Run(variant.name, func(t *testing.T) {
apiKey := tc.vendorKey
if variant.legacyKey {
apiKey = "sk-legacy"
} else if variant.gateway {
apiKey = "sk-gateway"
}
authHeader := apiKey
if variant.gateway && !variant.legacyKey {
authHeader = "Bearer " + apiKey
}
ctx := map[string]any{"baseUrl": base, "apiKey": apiKey, "authHeader": authHeader, "publicTaskId": "task_pub", "requestHeaders": map[string]any{}, "files": []any{}}
for key, value := range tc.driver {
ctx[key] = value
}
if variant.upstream != nil {
ctx["upstream"] = variant.upstream
}
wantSubmit, wantQuery := tc.vendorSubmit, tc.vendorQuery
if variant.gateway {
wantSubmit, wantQuery = tc.gatewaySubmit, tc.gatewayQuery
}
submit := call("buildSubmitRequest", ctx)
assert.Equal(t, base+wantSubmit, submit["url"])
headers, _ := submit["headers"].(map[string]any)
authorization, _ := headers["Authorization"].(string)
if variant.gateway {
assert.Equal(t, "Bearer "+apiKey, authorization, "a gateway receives its own token as a Bearer header")
} else {
assert.True(t, strings.HasPrefix(authorization, tc.vendorAuthPrefix), "vendor Authorization %q", authorization)
}
queryCtx := map[string]any{"taskId": "tid", "publicTaskId": "task_pub", "action": tc.driver["action"], "model": tc.driver["model"], "upstreamModel": tc.driver["upstreamModel"], "baseUrl": base, "apiKey": apiKey, "authHeader": authHeader, "data": nil, "state": nil}
if variant.upstream != nil {
queryCtx["upstream"] = variant.upstream
}
var query map[string]any
if plugin.Meta.FetchMode == "batch" {
query = call("buildBatchQueryRequest", queryCtx, []any{queryCtx})
} else {
query = call("buildQueryRequest", queryCtx)
}
assert.Equal(t, base+wantQuery, query["url"])
if tc.content == "" {
return
}
contentCtx := map[string]any{"baseUrl": base, "apiKey": apiKey, "authHeader": authHeader, "artifactKey": "video", "upstreamTaskId": "tid", "data": map[string]any{}, "clientRequest": map[string]any{"method": "GET", "headers": map[string]any{}}}
if variant.upstream != nil {
contentCtx["upstream"] = variant.upstream
}
assert.Equal(t, base+tc.content, call("buildContentRequest", contentCtx)["url"])
})
}
})
}
t.Run("alibaba asks only DashScope for an interleaved image stream", func(t *testing.T) {
plugin, found := generation.Get("alibaba")
require.True(t, found)
for _, variant := range []struct {
name string
upstream map[string]any
wantResponseType string
wantSSEHeader bool
}{
{"vendor", map[string]any{"kind": "vendor"}, "sse", true},
{"new_api", map[string]any{"kind": "new_api"}, "json", false},
} {
t.Run(variant.name, func(t *testing.T) {
value, err := plugin.Engine.Call(t.Context(), "buildSubmitRequest", map[string]any{
"baseUrl": base, "apiKey": "key", "authHeader": "key", "publicTaskId": "task_pub", "upstream": variant.upstream,
"model": "wan2.6-image", "upstreamModel": "wan2.6-image",
"requestBody": map[string]any{"model": "wan2.6-image", "prompt": "a cat", "metadata": map[string]any{"upstream_mode": "sync", "parameters": map[string]any{"enable_interleave": true}}},
})
require.NoError(t, err)
encoded, err := common.Marshal(value)
require.NoError(t, err)
var descriptor struct {
URL string `json:"url"`
ResponseType string `json:"responseType"`
Headers map[string]string `json:"headers"`
}
require.NoError(t, common.Unmarshal(encoded, &descriptor))
assert.Equal(t, variant.wantResponseType, descriptor.ResponseType, "a gateway native route aggregates the vendor stream and answers with JSON")
_, hasSSEHeader := descriptor.Headers["X-DashScope-Sse"]
assert.Equal(t, variant.wantSSEHeader, hasSSEHeader)
})
}
})
}