Skip to content

fix: detect responses SSE without content type - #6082

Draft
zhukangfeng wants to merge 4 commits into
QuantumNous:mainfrom
zhukangfeng:codex/fix-codex-sse-content-type
Draft

fix: detect responses SSE without content type#6082
zhukangfeng wants to merge 4 commits into
QuantumNous:mainfrom
zhukangfeng:codex/fix-codex-sse-content-type

Conversation

@zhukangfeng

@zhukangfeng zhukangfeng commented Jul 10, 2026

Copy link
Copy Markdown

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

This PR was AI-assisted by Codex automation because the configured git author is not a recurring core maintainer in recent repository history.

Fixes the chat/completions → responses conversion path for upstream Responses SSE bodies that omit Content-Type, as reported for Codex/ChatGPT subscription channels. The relay now peeks at the beginning of the response body when the header does not identify an event stream, treats event: or data: prefixes as SSE, and preserves the buffered bytes so the selected stream handler receives the full original body. JSON-looking bodies remain on the non-stream path.

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

✅ 提交前检查项 / Checklist

📸 运行证明 / Proof of Work

go test ./relay -run 'TestDetectResponsesEventStream|TestIsResponsesEventStreamContentType'
ok  	github.com/QuantumNous/new-api/relay	1.086s

go test ./relay ./relay/channel/openai
ok  	github.com/QuantumNous/new-api/relay	0.859s
ok  	github.com/QuantumNous/new-api/relay/channel/openai	0.465s

go test ./relay/...
ok  	github.com/QuantumNous/new-api/relay	(cached)
ok  	github.com/QuantumNous/new-api/relay/channel	2.196s
ok  	github.com/QuantumNous/new-api/relay/channel/advancedcustom	1.096s
ok  	github.com/QuantumNous/new-api/relay/channel/aws	4.942s
ok  	github.com/QuantumNous/new-api/relay/channel/claude	6.019s
ok  	github.com/QuantumNous/new-api/relay/channel/gemini	3.723s
ok  	github.com/QuantumNous/new-api/relay/channel/minimax	7.418s
ok  	github.com/QuantumNous/new-api/relay/channel/moonshot	11.237s
ok  	github.com/QuantumNous/new-api/relay/channel/ollama	14.891s
ok  	github.com/QuantumNous/new-api/relay/channel/openai	(cached)
ok  	github.com/QuantumNous/new-api/relay/channel/task/ali	9.031s
ok  	github.com/QuantumNous/new-api/relay/common	13.554s
ok  	github.com/QuantumNous/new-api/relay/helper	15.294s

git diff --check
# no output

Summary by CodeRabbit

  • Bug Fixes

    • Improved streamed-response handling when the upstream Content-Type header is missing or unclear by detecting event-stream–formatted payloads from the body.
    • Ensures the original response body remains readable for downstream processing.
    • Prevents JSON responses from being incorrectly treated as event streams, even when content type is incomplete.
  • Tests

    • Added coverage for event-stream detection with missing Content-Type, including leading whitespace and UTF-8 BOM cases.
    • Added coverage confirming JSON payloads stay non-stream and the body can still be read afterward.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The chat-to-responses relay now detects SSE payloads by inspecting response bodies when Content-Type is inconclusive. It preserves peeked bytes for downstream readers and adds coverage for SSE and JSON responses.

Changes

Responses SSE Detection

Layer / File(s) Summary
Stream detection and relay integration
relay/chat_completions_via_responses.go
Adds buffered response-body inspection for event: and data: prefixes. It preserves the response body after peeking and uses the detector to select the streaming handler.
Detection behavior tests
relay/chat_completions_via_responses_test.go
Tests headerless SSE detection, prompt return after an SSE prefix, whitespace and BOM handling, JSON rejection, and response-body preservation.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: calcium-ion

Poem

A rabbit peeks where stream bytes flow,
Finds event signs in rows below.
SSE stays whole, JSON stays right,
The relay chooses the path in sight.
Nibble, hop—the bytes take flight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes detecting Responses SSE without relying on the Content-Type header.
Linked Issues check ✅ Passed The changes satisfy issue #6075 by detecting headerless SSE, preserving inspected bytes, avoiding blocking, and retaining JSON handling.
Out of Scope Changes check ✅ Passed The changes remain within scope by modifying only Responses conversion detection and adding targeted regression tests.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@relay/chat_completions_via_responses.go`:
- Around line 199-213: Increase the Peek window in the response stream detection
logic to a fixed size larger than len("event:"), sufficient for the BOM and
leading whitespace handled by TrimLeft. Update the reader.Peek call in the
relevant detection block while preserving the existing short-body and error
handling, then continue trimming and checking for "event:" or "data:" prefixes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 97e3388f-d23f-48d6-9192-b908e275bd46

📥 Commits

Reviewing files that changed from the base of the PR and between 4e57038 and 490c41d.

📒 Files selected for processing (2)
  • relay/chat_completions_via_responses.go
  • relay/chat_completions_via_responses_test.go

Comment thread relay/chat_completions_via_responses.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@relay/chat_completions_via_responses.go`:
- Around line 203-205: Replace the fixed-size Peek(64) in the response sniffing
flow with incremental probing that can identify event: or data: from a short
live SSE prefix without waiting for EOF or a full buffer. Preserve existing
whitespace/BOM and JSON detection behavior, and add a regression test covering a
short SSE prefix such as event: ping\n\n with no EOF.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: afb16774-87c8-4073-aa86-6b9145d1c2ec

📥 Commits

Reviewing files that changed from the base of the PR and between a28dd2b and cc8ed95.

📒 Files selected for processing (2)
  • relay/chat_completions_via_responses.go
  • relay/chat_completions_via_responses_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • relay/chat_completions_via_responses_test.go

Comment thread relay/chat_completions_via_responses.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
relay/chat_completions_via_responses_test.go (1)

70-76: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a timeout branch to the select statement.

The select at Lines 70-75 waits only on result and reader.secondRead. If detectResponsesEventStream regresses to a state where it neither returns nor triggers a second Read (for example, a deadlock inside the detection loop), this test hangs until the Go test binary's global timeout instead of failing fast with a clear message.

Add a time.After branch so a regression fails quickly with a clear message.

♻️ Proposed fix to add a timeout branch
+	"time"
...
 	select {
 	case got := <-result:
 		assert.True(t, got)
 	case <-reader.secondRead:
 		require.Fail(t, "stream detection waited for more bytes after receiving an SSE prefix")
+	case <-time.After(2 * time.Second):
+		require.Fail(t, "detectResponsesEventStream did not complete in time")
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@relay/chat_completions_via_responses_test.go` around lines 70 - 76, Add a
timeout case to the select in the test around detectResponsesEventStream, using
time.After to fail promptly with a clear deadlock or detection-timeout message.
Preserve the existing result-success and secondRead-failure branches.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@relay/chat_completions_via_responses_test.go`:
- Around line 70-76: Add a timeout case to the select in the test around
detectResponsesEventStream, using time.After to fail promptly with a clear
deadlock or detection-timeout message. Preserve the existing result-success and
secondRead-failure branches.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ba8aac20-8473-441c-a18c-42933f2f41c8

📥 Commits

Reviewing files that changed from the base of the PR and between cc8ed95 and 305e27c.

📒 Files selected for processing (2)
  • relay/chat_completions_via_responses.go
  • relay/chat_completions_via_responses_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • relay/chat_completions_via_responses.go

@Calcium-Ion
Calcium-Ion force-pushed the main branch 2 times, most recently from 51fdfc5 to 2b6f1df Compare August 30, 2026 15:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant