feat: publish sanitized custom.97 source
This commit is contained in:
1022 files changed
+69903
-19207
No files matched your search
+137
-10
@@ -12,12 +12,14 @@ import (
|
||||
|
||||
"github.com/QuantumNous/new-api/common"
|
||||
"github.com/QuantumNous/new-api/constant"
|
||||
"github.com/QuantumNous/new-api/model"
|
||||
"github.com/QuantumNous/new-api/relay/channel"
|
||||
"github.com/QuantumNous/new-api/relay/channel/claude"
|
||||
"github.com/QuantumNous/new-api/relay/channel/gemini"
|
||||
"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/relay/helper"
|
||||
"github.com/QuantumNous/new-api/relaykit/dto"
|
||||
"github.com/QuantumNous/new-api/relaykit/types"
|
||||
"github.com/QuantumNous/new-api/service"
|
||||
@@ -242,7 +244,14 @@ func TestResponseModelComparisonAndLog(t *testing.T) {
|
||||
{name: "mapped case differs", models: []string{"MAPPED"}, returned: "MAPPED"},
|
||||
{name: "mapped prefix", models: []string{"mapped-2026-09-01"}, returned: "mapped-2026-09-01"},
|
||||
{name: "reverse prefix still warns", models: []string{"request"}, returned: "request", mismatch: true},
|
||||
{name: "substring still warns", models: []string{"other-requested"}, returned: "other-requested", mismatch: true},
|
||||
{name: "suffix", models: []string{"other-requested"}, returned: "other-requested"},
|
||||
{name: "provider path", models: []string{"vendor/requested"}, returned: "vendor/requested"},
|
||||
{name: "provider path case differs", models: []string{"vendor/REQUESTED"}, returned: "vendor/REQUESTED"},
|
||||
{name: "provider path with dated mapped model", models: []string{"vendor/mapped-2026-09-01"}, returned: "vendor/mapped-2026-09-01", mismatch: true},
|
||||
{name: "nested provider path", models: []string{"accounts/vendor/models/requested"}, returned: "accounts/vendor/models/requested"},
|
||||
{name: "provider path reverse prefix still warns", models: []string{"vendor/request"}, returned: "vendor/request", mismatch: true},
|
||||
{name: "provider path other model still warns", models: []string{"vendor/other"}, returned: "vendor/other", mismatch: true},
|
||||
{name: "provider path only still warns", models: []string{"vendor/"}, returned: "vendor/", mismatch: true},
|
||||
{name: "compatible difference survives matching frames", models: []string{"mapped", "Requested", "", "requested"}, returned: "Requested"},
|
||||
{name: "warning supersedes compatible difference", models: []string{"Requested", "other"}, returned: "other", mismatch: true},
|
||||
{name: "compatible difference cannot erase warning", models: []string{"other", "Requested"}, returned: "other", mismatch: true},
|
||||
@@ -268,8 +277,10 @@ func TestResponseModelComparisonAndLog(t *testing.T) {
|
||||
}
|
||||
require.NotNil(t, stored.ResponseModel)
|
||||
assert.Equal(t, &relaycommon.ResponseModel{
|
||||
RequestedModel: "requested", UpstreamModel: "mapped", ReturnedModel: tc.returned, Mismatch: tc.mismatch,
|
||||
RequestedModel: "requested", UpstreamModel: "mapped", ReturnedModel: tc.returned,
|
||||
}, stored.ResponseModel)
|
||||
assert.NotContains(t, other.JSONString(), "mismatch")
|
||||
assert.Equal(t, tc.mismatch, stored.ResponseModel.Mismatch())
|
||||
assert.Equal(t, "mapped", info.UpstreamModelName)
|
||||
})
|
||||
}
|
||||
@@ -321,7 +332,33 @@ func TestResponseModelEmptyExpectedNamesDoNotMatchEveryPrefix(t *testing.T) {
|
||||
}
|
||||
info.ObserveResponseModel("other")
|
||||
require.NotNil(t, info.ResponseModel)
|
||||
assert.True(t, info.ResponseModel.Mismatch)
|
||||
assert.True(t, info.ResponseModel.Mismatch())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResponseModelExpectedProviderPath(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
requested string
|
||||
upstream string
|
||||
returned string
|
||||
mismatch bool
|
||||
}{
|
||||
{name: "requested carries provider path", requested: "vendor/requested", returned: "requested", mismatch: true},
|
||||
{name: "same provider path on both sides", requested: "vendor/requested", returned: "vendor/requested-2026-09-01"},
|
||||
{name: "provider path alone does not match", requested: "vendor/requested", returned: "vendor", mismatch: true},
|
||||
{name: "different model behind same provider still warns", requested: "vendor/requested", returned: "vendor/other", mismatch: true},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
info := &relaycommon.RelayInfo{
|
||||
OriginModelName: tc.requested,
|
||||
ChannelMeta: &relaycommon.ChannelMeta{UpstreamModelName: tc.upstream},
|
||||
}
|
||||
info.ObserveResponseModel(tc.returned)
|
||||
require.NotNil(t, info.ResponseModel)
|
||||
assert.Equal(t, tc.returned, info.ResponseModel.ReturnedModel)
|
||||
assert.Equal(t, tc.mismatch, info.ResponseModel.Mismatch())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -332,11 +369,11 @@ func TestResponseModelRetryResetsObservation(t *testing.T) {
|
||||
info := &relaycommon.RelayInfo{OriginModelName: "requested"}
|
||||
info.InitChannelMeta(c)
|
||||
info.ObserveResponseModel("other")
|
||||
require.True(t, info.ResponseModel.Mismatch)
|
||||
require.True(t, info.ResponseModel.Mismatch())
|
||||
info.InitChannelMeta(c)
|
||||
assert.Nil(t, info.ResponseModel)
|
||||
info.ObserveResponseModel("requested")
|
||||
assert.False(t, info.ResponseModel.Mismatch)
|
||||
assert.False(t, info.ResponseModel.Mismatch())
|
||||
}
|
||||
|
||||
func TestResponseModelHandlersCaptureBeforeConversion(t *testing.T) {
|
||||
@@ -397,7 +434,8 @@ func TestResponseModelHandlersCaptureBeforeConversion(t *testing.T) {
|
||||
require.NotNil(t, usage)
|
||||
assert.Equal(t, 5, usage.TotalTokens)
|
||||
require.NotNil(t, info.ResponseModel)
|
||||
assert.Equal(t, &relaycommon.ResponseModel{RequestedModel: "requested", UpstreamModel: "mapped", ReturnedModel: "returned", Mismatch: true}, info.ResponseModel)
|
||||
assert.Equal(t, &relaycommon.ResponseModel{RequestedModel: "requested", UpstreamModel: "mapped", ReturnedModel: "returned"}, info.ResponseModel)
|
||||
assert.True(t, info.ResponseModel.Mismatch())
|
||||
other := service.GenerateTextOtherInfo(c, info, 1, 1, 1, 0, 0, 0, 1)
|
||||
assert.Equal(t, *info.ResponseModel, other.Snapshot()["response_model"])
|
||||
})
|
||||
@@ -409,11 +447,11 @@ func TestResponseModelSharedResponsesAccumulator(t *testing.T) {
|
||||
// terminal must not erase the model declared before an interrupted stream.
|
||||
info := &relaycommon.RelayInfo{OriginModelName: "requested", ChannelMeta: &relaycommon.ChannelMeta{UpstreamModelName: "mapped"}}
|
||||
accumulator := service.NewResponsesUsageAccumulator(info)
|
||||
accumulator.Observe(&dto.ResponsesStreamResponse{Type: "response.created", Response: &dto.OpenAIResponsesResponse{Model: "returned"}})
|
||||
accumulator.Observe(&dto.ResponsesStreamResponse{Type: "response.failed", Response: &dto.OpenAIResponsesResponse{Usage: &dto.Usage{InputTokens: 2, OutputTokens: 3}}})
|
||||
accumulator.Observe(&dto.ResponsesStreamResponse{Type: "response.created", Response: &dto.OpenAIResponsesResponse{Model: "returned"}}, nil)
|
||||
accumulator.Observe(&dto.ResponsesStreamResponse{Type: "response.failed", Response: &dto.OpenAIResponsesResponse{Usage: &dto.Usage{InputTokens: 2, OutputTokens: 3}}}, nil)
|
||||
assert.Equal(t, 5, accumulator.Finish().TotalTokens)
|
||||
require.NotNil(t, info.ResponseModel)
|
||||
assert.True(t, info.ResponseModel.Mismatch)
|
||||
assert.True(t, info.ResponseModel.Mismatch())
|
||||
assert.Equal(t, "returned", info.ResponseModel.ReturnedModel)
|
||||
}
|
||||
|
||||
@@ -440,8 +478,97 @@ func TestAstraDetectionCanBeDisabledIndependently(t *testing.T) {
|
||||
require.False(t, shouldEnableAstraResponseGuard("/v1/responses", info))
|
||||
} else {
|
||||
require.NotNil(t, info.ResponseModel)
|
||||
require.True(t, info.ResponseModel.Mismatch)
|
||||
require.True(t, info.ResponseModel.Mismatch())
|
||||
require.True(t, shouldEnableAstraResponseGuard("/v1/responses", info))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpstreamTimingResponsesGuardAndScope(t *testing.T) {
|
||||
service.InitHttpClient()
|
||||
previous := constant.StreamingTimeout
|
||||
constant.StreamingTimeout = 30
|
||||
t.Cleanup(func() { constant.StreamingTimeout = previous })
|
||||
for _, tc := range []struct {
|
||||
name, group, model string
|
||||
guard bool
|
||||
}{
|
||||
{"guard accepted", "gpt-s-unstable", "gpt-6-astra", true},
|
||||
{"guard rejected", "gpt-s-unstable", "gpt-5.6-luna", true},
|
||||
{"without guard", "gpt-s-unstable", "gpt-6-astra", false},
|
||||
{"other group", "gpt-v-pro", "gpt-6-astra", true},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
payload := ": keepalive\n\ndata: {\"type\":\"response.in_progress\",\"response\":{}}\n\n" +
|
||||
"data: {\"type\":\"response.created\",\"response\":{\"model\":\"" + tc.model + "\"}}\n\n"
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = io.Copy(io.Discard, r.Body)
|
||||
w.Header().Set("Content-Type", "text/event-stream")
|
||||
_, _ = io.WriteString(w, payload)
|
||||
}))
|
||||
defer server.Close()
|
||||
writer := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(writer)
|
||||
c.Request = httptest.NewRequest("POST", "/v1/responses", strings.NewReader("{}"))
|
||||
info := &relaycommon.RelayInfo{
|
||||
StartTime: time.Now(), UsingGroup: tc.group, AstraAutoSwitch: tc.guard,
|
||||
ChannelMeta: &relaycommon.ChannelMeta{ChannelId: 1}, IsStream: true,
|
||||
}
|
||||
if tc.guard {
|
||||
info.ResponseGuard = &relaycommon.ResponseModelGuard{}
|
||||
}
|
||||
req, err := http.NewRequest("POST", server.URL, strings.NewReader("{}"))
|
||||
require.NoError(t, err)
|
||||
resp, err := channel.DoRequest(c, req, info)
|
||||
assert.False(t, c.Writer.Written(), "model confirmation must not deliver buffered data")
|
||||
if tc.guard && tc.model != "gpt-6-astra" {
|
||||
require.Error(t, err)
|
||||
require.Nil(t, resp)
|
||||
snapshot := info.UpstreamTiming.Snapshot()
|
||||
events := snapshot["events_ms"].(map[string]float64)
|
||||
assert.Contains(t, events, "first_sse_data")
|
||||
assert.NotContains(t, events, "model_confirmed")
|
||||
assert.NotContains(t, events, "first_downstream_flush")
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, payload, string(body), "instrumentation preserves every upstream byte")
|
||||
resp.Body = io.NopCloser(strings.NewReader(string(body)))
|
||||
helper.StreamScannerHandler(c, resp, info, func(data string, sr *helper.StreamResult) {
|
||||
assert.NoError(t, helper.ResponseChunkData(c, dto.ResponsesStreamResponse{Type: "response.created"}, data))
|
||||
})
|
||||
assert.Contains(t, writer.Body.String(), tc.model)
|
||||
other := model.NewLogOther()
|
||||
service.AppendRelayLogAdminInfo(c, info, other)
|
||||
logData := other.Snapshot()
|
||||
assert.NotContains(t, logData, "upstream_timing")
|
||||
admin := logData["admin_info"].(map[string]any)
|
||||
if tc.group != "gpt-s-unstable" {
|
||||
assert.Nil(t, info.UpstreamTiming)
|
||||
assert.NotContains(t, admin, "upstream_timing")
|
||||
return
|
||||
}
|
||||
require.NotNil(t, info.UpstreamTiming)
|
||||
snapshot := admin["upstream_timing"].(map[string]any)
|
||||
events := snapshot["events_ms"].(map[string]float64)
|
||||
ordered := []string{"upstream_start", "get_connection", "connection_ready", "request_sent", "response_first_byte", "response_headers", "first_sse_data"}
|
||||
if tc.guard {
|
||||
ordered = append(ordered, "model_confirmed")
|
||||
}
|
||||
ordered = append(ordered, "first_downstream_flush")
|
||||
for i, key := range ordered {
|
||||
require.Contains(t, events, key)
|
||||
if i > 0 {
|
||||
assert.GreaterOrEqual(t, events[key], events[ordered[i-1]], key)
|
||||
}
|
||||
}
|
||||
assert.EqualValues(t, 2, snapshot["request_body_bytes"])
|
||||
assert.Equal(t, "HTTP/1.1", snapshot["protocol"])
|
||||
assert.Equal(t, 1, snapshot["write_count"])
|
||||
assert.Equal(t, false, snapshot["write_failed"])
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user