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

@@ -5,13 +5,16 @@ import (
"io"
"net/http"
"net/http/httptest"
"slices"
"strings"
"testing"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/constant"
relaycommon "github.com/QuantumNous/new-api/relay/common"
relayconstant "github.com/QuantumNous/new-api/relay/constant"
"github.com/QuantumNous/new-api/relaykit/dto"
"github.com/QuantumNous/new-api/relaykit/types"
"github.com/QuantumNous/new-api/setting/operation_setting"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
@@ -193,7 +196,7 @@ func TestOaiResponsesHandlerCountsCompletedImageGenerationOutputs(t *testing.T)
assert.False(t, c.GetBool("image_generation_call"))
}
func TestOaiResponsesHandlerIncompleteStatusCommitsZeroImageGeneration(t *testing.T) {
func TestOaiResponsesHandlerCountsImageGenerationOnIncompleteStatus(t *testing.T) {
gin.SetMode(gin.TestMode)
body, err := common.Marshal(dto.OpenAIResponsesResponse{
@@ -229,7 +232,7 @@ func TestOaiResponsesHandlerIncompleteStatusCommitsZeroImageGeneration(t *testin
_, apiErr := OaiResponsesHandler(c, info, resp)
require.Nil(t, apiErr)
assert.Equal(t, 0, info.ResponsesUsageInfo.BuiltInTools[dto.BuildInToolImageGeneration].CallCount)
assert.Equal(t, 1, info.ResponsesUsageInfo.BuiltInTools[dto.BuildInToolImageGeneration].CallCount)
}
func runResponsesImageBillingStream(t *testing.T, events ...string) *relaycommon.RelayInfo {
@@ -284,14 +287,14 @@ func TestOaiResponsesStreamHandlerDeduplicatesCompletedImageOutput(t *testing.T)
assert.Equal(t, 1, info.ResponsesUsageInfo.BuiltInTools[dto.BuildInToolImageGeneration].CallCount)
}
func TestOaiResponsesStreamHandlerDiscardsImageOutputOnIncomplete(t *testing.T) {
func TestOaiResponsesStreamHandlerCountsImageOutputOnIncomplete(t *testing.T) {
info := runResponsesImageBillingStream(
t,
`{"type":"response.output_item.done","output_index":0,"item":{"type":"image_generation_call","id":"img_1","status":"completed","result":"base64-a"}}`,
`{"type":"response.incomplete","response":{"status":"incomplete"}}`,
)
assert.Equal(t, 0, info.ResponsesUsageInfo.BuiltInTools[dto.BuildInToolImageGeneration].CallCount)
assert.Equal(t, 1, info.ResponsesUsageInfo.BuiltInTools[dto.BuildInToolImageGeneration].CallCount)
}
func TestOaiResponsesStreamHandlerDoesNotCountPartialImageEvent(t *testing.T) {
@@ -392,3 +395,139 @@ func TestOaiResponsesStreamHandlerKeepsNonSGLangCreatedAt(t *testing.T) {
require.Nil(t, apiErr)
assert.Contains(t, w.Body.String(), `1786588600.0`)
}
func TestResponsesStreamFailureHidesRoutingDetails(t *testing.T) {
for _, eventType := range []string{"error", "response.error", "response.failed"} {
t.Run(eventType, func(t *testing.T) {
secret := "智能路由流式响应中途失败。原因:个人池商家在流式响应开始后中断。 request_id: upstream-private-id"
original := map[string]any{"type": eventType, "sequence_number": 3, "code": "vendor_stream_error", "message": secret, "debug": secret, "error": map[string]any{"message": secret}, "response": map[string]any{"id": "resp_test", "status": "failed", "error": map[string]any{"type": "vendor_error", "code": "vendor_stream_error", "message": secret}, "usage": map[string]any{"input_tokens": 10, "output_tokens": 2}, "debug": secret}}
encoded, err := common.Marshal(original)
require.NoError(t, err)
var event dto.ResponsesStreamResponse
require.NoError(t, common.Unmarshal(encoded, &event))
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest(http.MethodPost, "/v1/responses", nil)
c.Set(common.RequestIdKey, "local-request-id")
sendResponsesStreamData(c, event, string(encoded))
body := w.Body.String()
assert.Contains(t, body, "event: "+eventType)
assert.Contains(t, body, "model_service_error")
assert.Contains(t, body, "local-request-id")
assert.Contains(t, body, `"status":"failed"`)
assert.Contains(t, body, `"input_tokens":10`)
for _, detail := range []string{"个人池", "智能路由", "upstream-private-id", "vendor_stream_error", "debug"} {
assert.NotContains(t, body, detail)
}
// Projection must not change the event used for outcome and billing.
require.NotNil(t, event.Response)
assert.Equal(t, "vendor_stream_error", event.Response.GetOpenAIError().Code)
})
}
}
func TestResponsesSuccessfulStreamDataUnchanged(t *testing.T) {
body := `{"type":"response.output_text.delta","delta":"个人池 is user content"}`
var event dto.ResponsesStreamResponse
require.NoError(t, common.UnmarshalJsonStr(body, &event))
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest(http.MethodPost, "/v1/responses", nil)
sendResponsesStreamData(c, event, body)
assert.Contains(t, w.Body.String(), body)
}
// A converted hosted web search reaches Azure and Xinference Chat Completions
// as web_search_options, like OpenAI; the upstream decides whether it applies.
// Azure Responses bills web search by tool_usage.web_search.num_requests (Bing
// transactions) under bing_web_search, and the explicit zeros silence the
// web_search_call items, which leaves one surcharge row.
func TestAzureHostedWebSearch(t *testing.T) {
gin.SetMode(gin.TestMode)
oldTimeout := constant.StreamingTimeout
constant.StreamingTimeout = 30
t.Cleanup(func() {
constant.StreamingTimeout = oldTimeout
})
t.Run("Claude to Chat", func(t *testing.T) {
const body = `{"model":"gpt-5.1","max_tokens":64,"messages":[{"role":"user","content":"Weather?"}],"tools":[{"type":"web_search_20250305","name":"web_search"}]}`
for _, channelType := range []int{constant.ChannelTypeAzure, constant.ChannelTypeXinference, constant.ChannelTypeOpenAI} {
c, _ := gin.CreateTestContext(httptest.NewRecorder())
info := &relaycommon.RelayInfo{
RelayFormat: types.RelayFormatClaude,
ChannelMeta: &relaycommon.ChannelMeta{ChannelType: channelType, UpstreamModelName: "gpt-5.1"},
}
adaptor := &Adaptor{}
adaptor.Init(info)
var request dto.ClaudeRequest
require.NoError(t, common.UnmarshalJsonStr(body, &request))
converted, err := adaptor.ConvertClaudeRequest(c, info, &request)
require.NoError(t, err)
wire, err := common.Marshal(converted)
require.NoError(t, err)
assert.True(t, strings.Contains(string(wire), `"web_search_options"`), channelType)
var codes []string
for _, diagnostic := range info.ConversionDiagnostics() {
codes = append(codes, diagnostic.Code)
}
assert.False(t, slices.Contains(codes, "hosted_web_search_omitted"), channelType)
}
})
const searchCall = `{"type":"web_search_call","status":"completed","action":{"type":"search","query":"go"}}`
const usage = `"usage":{"input_tokens":10,"output_tokens":3,"total_tokens":13},"tool_usage":{"web_search":{"num_requests":5}}`
output := strings.Repeat(searchCall+",", 3) + `{"type":"message","role":"assistant","content":[{"type":"output_text","text":"Go 1.25"}]}`
tests := []struct {
name string
contentType string
body string
}{
{
name: "json",
contentType: "application/json",
body: `{"id":"resp_1","object":"response","model":"gpt-5.1","status":"completed","output":[` + output + `],` + usage + `}`,
},
{
name: "stream",
contentType: "text/event-stream",
body: strings.Repeat(`data: {"type":"response.output_item.done","output_index":0,"item":`+searchCall+"}\n\n", 3) +
`data: {"type":"response.completed","response":{"id":"resp_1","object":"response","model":"gpt-5.1","status":"completed","output":[` + output + `],` + usage + "}}\n\ndata: [DONE]\n\n",
},
}
for _, tt := range tests {
t.Run("Responses "+tt.name, func(t *testing.T) {
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request = httptest.NewRequest(http.MethodPost, "/v1/responses", nil)
info := &relaycommon.RelayInfo{
RelayMode: relayconstant.RelayModeResponses,
RelayFormat: types.RelayFormatOpenAIResponses,
OriginModelName: "gpt-5.1",
IsStream: tt.name == "stream",
DisablePing: true,
ChannelMeta: &relaycommon.ChannelMeta{ChannelType: constant.ChannelTypeAzure, UpstreamModelName: "gpt-5.1"},
}
adaptor := &Adaptor{}
adaptor.Init(info)
resp := &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(strings.NewReader(tt.body)),
Header: http.Header{"Content-Type": []string{tt.contentType}},
}
var apiErr *types.NewAPIError
if info.IsStream {
_, apiErr = OaiResponsesStreamHandler(c, info, resp)
} else {
_, apiErr = OaiResponsesHandler(c, info, resp)
}
require.Nil(t, apiErr)
billed := map[string]int{}
for name, tool := range info.ResponsesUsageInfo.BuiltInTools {
if tool.CallCount > 0 {
billed[name] = tool.CallCount
}
}
assert.Equal(t, map[string]int{"bing_web_search": 5}, billed)
})
}
}