From 01062c324429636b36d349036fdf2d08e1dce699 Mon Sep 17 00:00:00 2001 From: wucm667 Date: Sun, 19 Jul 2026 22:28:49 +0800 Subject: [PATCH] fix(openai): correct buffered messages content type --- .../service/openai_compat_model_test.go | 38 +++++++++++++++++++ .../service/openai_gateway_messages.go | 1 + 2 files changed, 39 insertions(+) diff --git a/backend/internal/service/openai_compat_model_test.go b/backend/internal/service/openai_compat_model_test.go index e1007c507..c7f82d7c3 100644 --- a/backend/internal/service/openai_compat_model_test.go +++ b/backend/internal/service/openai_compat_model_test.go @@ -3,6 +3,7 @@ package service import ( "bytes" "context" + "encoding/json" "errors" "fmt" "io" @@ -1721,6 +1722,43 @@ func TestForwardAsAnthropic_BufferedTerminalWithoutUpstreamCloseReturns(t *testi } } +func TestHandleAnthropicBufferedStreamingResponse_OverridesUpstreamContentType(t *testing.T) { + gin.SetMode(gin.TestMode) + + rec := httptest.NewRecorder() + c, _ := gin.CreateTestContext(rec) + c.Request = httptest.NewRequest(http.MethodPost, "/v1/messages", nil) + + resp := &http.Response{ + StatusCode: http.StatusOK, + Header: http.Header{"Content-Type": []string{"text/event-stream"}}, + Body: io.NopCloser(strings.NewReader( + `data: {"type":"response.completed","response":{"id":"resp_buffered_json","object":"response","model":"gpt-5.4","status":"completed","output":[{"type":"message","id":"msg_1","role":"assistant","status":"completed","content":[{"type":"output_text","text":"ok"}]}],"usage":{"input_tokens":15,"output_tokens":6,"total_tokens":21,"input_tokens_details":{"cached_tokens":5}}}}` + "\n\n", + )), + } + cfg := &config.Config{} + svc := &OpenAIGatewayService{ + cfg: cfg, + responseHeaderFilter: compileResponseHeaderFilter(cfg), + } + + result, err := svc.handleAnthropicBufferedStreamingResponse( + resp, c, &Account{}, "claude-sonnet-4-5", "gpt-5.4", "gpt-5.4", time.Now(), + ) + require.NoError(t, err) + require.NotNil(t, result) + require.Equal(t, "application/json; charset=utf-8", rec.Header().Get("Content-Type")) + require.NotContains(t, rec.Header().Get("Content-Type"), "text/event-stream") + + var message apicompat.AnthropicResponse + require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &message)) + require.Equal(t, "message", message.Type) + require.Equal(t, "resp_buffered_json", message.ID) + require.Equal(t, 10, message.Usage.InputTokens) + require.Equal(t, 6, message.Usage.OutputTokens) + require.Equal(t, 5, message.Usage.CacheReadInputTokens) +} + func TestForwardAsAnthropic_BufferedEventNamedTerminalWithoutUpstreamCloseReturns(t *testing.T) { gin.SetMode(gin.TestMode) diff --git a/backend/internal/service/openai_gateway_messages.go b/backend/internal/service/openai_gateway_messages.go index f37f2997c..db9e95a8f 100644 --- a/backend/internal/service/openai_gateway_messages.go +++ b/backend/internal/service/openai_gateway_messages.go @@ -512,6 +512,7 @@ func (s *OpenAIGatewayService) handleAnthropicBufferedStreamingResponse( if s.responseHeaderFilter != nil { responseheaders.WriteFilteredHeaders(c.Writer.Header(), resp.Header, s.responseHeaderFilter) } + c.Header("Content-Type", "application/json; charset=utf-8") c.JSON(http.StatusOK, anthropicResp) return &OpenAIForwardResult{