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

+51 -12
View File
@@ -79,6 +79,9 @@ func OaiChatToResponsesStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
return nil, types.NewOpenAIError(err, types.ErrorCodeBadResponse, http.StatusInternalServerError)
}
streamErr := (*types.NewAPIError)(nil)
// upstreamFailure is the upstream or conversion failure the client was
// told about with response.failed.
var upstreamFailure *types.NewAPIError
sendEvent := func(event relayconvert.ChatToResponsesStreamEvent) bool {
data, err := common.Marshal(event.Payload)
@@ -87,6 +90,13 @@ func OaiChatToResponsesStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
return false
}
if err := helper.ResponseChunkData(c, dto.ResponsesStreamResponse{Type: event.Type}, string(data)); err != nil {
// When the client went away the upstream already produced output,
// so the stream stops and settles normally instead of failing; any
// other write error stays a server error.
if c.Request.Context().Err() != nil {
info.StreamStatus.SetEndReason(relaycommon.StreamEndReasonClientGone, err)
return false
}
streamErr = types.NewOpenAIError(err, types.ErrorCodeBadResponse, http.StatusInternalServerError)
return false
}
@@ -112,7 +122,7 @@ func OaiChatToResponsesStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
helper.StreamScannerHandler(c, resp, info, func(data string, sr *helper.StreamResult) {
if streamErr != nil {
sr.Stop(streamErr)
stopStream(sr, streamErr)
return
}
@@ -120,24 +130,28 @@ func OaiChatToResponsesStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
if err := common.UnmarshalJsonStr(data, &errorResp); err == nil {
if oaiError := errorResp.GetOpenAIError(); oaiError != nil && oaiError.Type != "" {
if failResponsesStream(fmt.Errorf("%s", oaiError.Message)) {
sr.Stop(streamErr)
// The client got response.failed, so the request is never
// retried; the recorded error keeps the stream failed.
upstreamFailure = types.WithOpenAIError(*oaiError, http.StatusInternalServerError, types.ErrOptionWithSkipRetry())
sr.Stop(upstreamFailure)
return
}
streamErr = types.WithOpenAIError(*oaiError, resp.StatusCode)
sr.Stop(streamErr)
stopStream(sr, streamErr)
return
}
}
var chunk dto.ChatCompletionsStreamResponse
if err := common.UnmarshalJsonStr(data, &chunk); err != nil {
logger.LogError(c, "failed to unmarshal chat stream response: "+err.Error())
logger.LogError(c, common.LogText("failed to unmarshal chat stream response: %s", err.Error()))
if failResponsesStream(err) {
sr.Stop(streamErr)
upstreamFailure = types.NewOpenAIError(err, types.ErrorCodeBadResponseBody, http.StatusInternalServerError, types.ErrOptionWithSkipRetry())
sr.Stop(upstreamFailure)
return
}
streamErr = types.NewOpenAIError(err, types.ErrorCodeBadResponseBody, http.StatusInternalServerError)
sr.Stop(streamErr)
stopStream(sr, streamErr)
return
}
@@ -145,22 +159,23 @@ func OaiChatToResponsesStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
results, err := service.ConvertStreamResponseChunk(c, info, state, &chunk)
if err != nil {
if failResponsesStream(err) {
sr.Stop(streamErr)
upstreamFailure = types.NewOpenAIError(err, types.ErrorCodeBadResponse, http.StatusInternalServerError, types.ErrOptionWithSkipRetry())
sr.Stop(upstreamFailure)
return
}
streamErr = types.NewOpenAIError(err, types.ErrorCodeBadResponse, http.StatusInternalServerError)
sr.Stop(streamErr)
stopStream(sr, streamErr)
return
}
for _, result := range results {
event, ok := result.Value.(relayconvert.ChatToResponsesStreamEvent)
if !ok {
streamErr = types.NewOpenAIError(fmt.Errorf("expected OAI responses stream event, got %T", result.Value), types.ErrorCodeBadResponse, http.StatusInternalServerError)
sr.Stop(streamErr)
stopStream(sr, streamErr)
return
}
if !sendEvent(event) {
sr.Stop(streamErr)
stopStream(sr, streamErr)
return
}
}
@@ -171,10 +186,19 @@ func OaiChatToResponsesStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
}
usage := state.Usage()
if usage == nil || usage.TotalTokens == 0 {
noUpstreamUsage := usage == nil || usage.TotalTokens == 0
if upstreamFailure != nil && noUpstreamUsage && state.UsageText() == "" {
// The stream failed before any output reached the client, which
// already received response.failed: the request is not charged.
return nil, upstreamFailure
}
if noUpstreamUsage {
usage = service.ResponseText2Usage(c, state.UsageText(), info.UpstreamModelName, info.GetEstimatePromptTokens())
state.SetUsage(usage)
}
if info.StreamStatus.EndReason == relaycommon.StreamEndReasonClientGone {
return usage, nil
}
finalResults, err := service.FinalizeStreamResponse(c, info, state)
if err != nil {
@@ -189,9 +213,24 @@ func OaiChatToResponsesStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
return nil, types.NewOpenAIError(fmt.Errorf("expected OAI responses stream event, got %T", result.Value), types.ErrorCodeBadResponse, http.StatusInternalServerError)
}
if !sendEvent(event) {
return nil, streamErr
if streamErr != nil {
return nil, streamErr
}
return usage, nil
}
}
return usage, nil
}
// stopStream ends a converted stream from the scanner callback. A nil
// streamErr (the stream stops because the client went away) must reach
// StreamResult.Stop as an untyped nil; a typed nil *NewAPIError is a non-nil
// error that StreamResult would record as a failure and dereference.
func stopStream(sr *helper.StreamResult, streamErr *types.NewAPIError) {
if streamErr == nil {
sr.Stop(nil)
return
}
sr.Stop(streamErr)
}