feat: sync deployed v1.0.0-rc.38-custom.42

Sync production source including routing, billing, Astra detection and public uptime. Update custom build instructions and license packaging.
This commit is contained in:
cneicy committed 2026-09-26 04:49:11 +08:00
1 parent aa6c3f50f4
commit ceddfd3d6b
828 files changed
+122253 -13702

No files matched your search

@@ -829,6 +829,143 @@ func TestAdaptorConvertsGeminiRequestToOpenAIChatUpstream(t *testing.T) {
assert.Equal(t, "user", chatReq.Messages[0].Role)
}
func TestAdaptorCrossProtocolChatUpstreamRequestsStreamUsage(t *testing.T) {
claudeReq := &dto.ClaudeRequest{
Model: "gpt-test",
Messages: []dto.ClaudeMessage{{Role: "user", Content: "hello"}},
}
geminiReq := &dto.GeminiChatRequest{
Contents: []dto.GeminiChatContent{{Role: "user", Parts: []dto.GeminiPart{{Text: "hello"}}}},
}
responsesReq := dto.OpenAIResponsesRequest{
Model: "gpt-test",
Input: mustAdvancedCustomRawMessage(t, "hello"),
}
tests := []struct {
name string
route dto.AdvancedCustomRoute
relayFormat types.RelayFormat
relayMode int
requestPath string
convert func(*Adaptor, *gin.Context, *relaycommon.RelayInfo) (any, error)
isStream bool
supportUsage bool
wantUsage bool
}{
{
name: "claude stream requests usage",
route: dto.AdvancedCustomRoute{
IncomingPath: "/v1/messages",
UpstreamPath: "/v1/chat/completions",
Converter: relayconvert.ConverterClaudeMessagesToOpenAIChat,
},
relayFormat: types.RelayFormatClaude,
relayMode: relayconstant.RelayModeChatCompletions,
requestPath: "/v1/messages",
convert: func(a *Adaptor, c *gin.Context, info *relaycommon.RelayInfo) (any, error) {
return a.ConvertClaudeRequest(c, info, claudeReq)
},
isStream: true,
supportUsage: true,
wantUsage: true,
},
{
name: "gemini stream requests usage",
route: dto.AdvancedCustomRoute{
IncomingPath: "/v1beta/models/{model}:generateContent",
UpstreamPath: "/v1/chat/completions",
Converter: relayconvert.ConverterGeminiContentToOpenAIChat,
},
relayFormat: types.RelayFormatGemini,
relayMode: relayconstant.RelayModeGemini,
requestPath: "/v1beta/models/gpt-test:generateContent",
convert: func(a *Adaptor, c *gin.Context, info *relaycommon.RelayInfo) (any, error) {
return a.ConvertGeminiRequest(c, info, geminiReq)
},
isStream: true,
supportUsage: true,
wantUsage: true,
},
{
name: "responses stream requests usage",
route: dto.AdvancedCustomRoute{
IncomingPath: "/v1/responses",
UpstreamPath: "/v1/chat/completions",
Converter: relayconvert.ConverterOpenAIResponsesToOpenAIChat,
},
relayFormat: types.RelayFormatOpenAIResponses,
relayMode: relayconstant.RelayModeResponses,
requestPath: "/v1/responses",
convert: func(a *Adaptor, c *gin.Context, info *relaycommon.RelayInfo) (any, error) {
return a.ConvertOpenAIResponsesRequest(c, info, responsesReq)
},
isStream: true,
supportUsage: true,
wantUsage: true,
},
{
name: "claude non-stream leaves stream options unset",
route: dto.AdvancedCustomRoute{
IncomingPath: "/v1/messages",
UpstreamPath: "/v1/chat/completions",
Converter: relayconvert.ConverterClaudeMessagesToOpenAIChat,
},
relayFormat: types.RelayFormatClaude,
relayMode: relayconstant.RelayModeChatCompletions,
requestPath: "/v1/messages",
convert: func(a *Adaptor, c *gin.Context, info *relaycommon.RelayInfo) (any, error) {
return a.ConvertClaudeRequest(c, info, claudeReq)
},
isStream: false,
supportUsage: true,
wantUsage: false,
},
{
name: "claude stream without stream options support",
route: dto.AdvancedCustomRoute{
IncomingPath: "/v1/messages",
UpstreamPath: "/v1/chat/completions",
Converter: relayconvert.ConverterClaudeMessagesToOpenAIChat,
},
relayFormat: types.RelayFormatClaude,
relayMode: relayconstant.RelayModeChatCompletions,
requestPath: "/v1/messages",
convert: func(a *Adaptor, c *gin.Context, info *relaycommon.RelayInfo) (any, error) {
return a.ConvertClaudeRequest(c, info, claudeReq)
},
isStream: true,
supportUsage: false,
wantUsage: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
adaptor := &Adaptor{}
info := advancedCustomRelayInfo(&dto.AdvancedCustomConfig{Routes: []dto.AdvancedCustomRoute{tt.route}})
info.RelayFormat = tt.relayFormat
info.RelayMode = tt.relayMode
info.RequestURLPath = tt.requestPath
info.IsStream = tt.isStream
info.SupportStreamOptions = tt.supportUsage
c := advancedCustomGinContext(tt.requestPath)
converted, err := tt.convert(adaptor, c, info)
require.NoError(t, err)
chatReq, ok := converted.(*dto.GeneralOpenAIRequest)
require.True(t, ok)
if !tt.wantUsage {
assert.Nil(t, chatReq.StreamOptions)
return
}
require.NotNil(t, chatReq.StreamOptions)
assert.True(t, chatReq.StreamOptions.IncludeUsage)
})
}
}
func advancedCustomRelayInfo(config *dto.AdvancedCustomConfig) *relaycommon.RelayInfo {
return &relaycommon.RelayInfo{
RelayFormat: types.RelayFormatOpenAI,