Skip to content

fix: finalize Claude streams after upstream EOF - #6721

Open
kuangzhenfeng wants to merge 1 commit into
QuantumNous:mainfrom
kuangzhenfeng:fix/claude-stream-eof
Open

fix: finalize Claude streams after upstream EOF#6721
kuangzhenfeng wants to merge 1 commit into
QuantumNous:mainfrom
kuangzhenfeng:fix/claude-stream-eof

Conversation

@kuangzhenfeng

@kuangzhenfeng kuangzhenfeng commented Aug 8, 2026

Copy link
Copy Markdown

📝 变更描述 / Description

修复 OpenAI 兼容流在发送 [DONE] 或直接 EOF、但没有可转换的终止 chunk 时,Claude Messages 流缺少结束事件的问题。

此前 HandleFinalResponse 处理最后一个普通 chunk 后会直接将转换状态标记为完成。若上游没有提供 finish_reason 终止 chunk,当前 content block 不会关闭,message_deltamessage_stop 也不会发送,Claude Code 等等待 Anthropic SSE 结束事件的客户端会一直停留在生成状态。

本次改动在处理最后一个 chunk 后调用现有的 Claude 流 finalizer,由转换状态统一补齐仍未发送的 content_block_stopmessage_deltamessage_stop。正常已完成的流会由 Done 状态阻止重复结束事件。

同时在 relayconvert 兼容入口中暴露 finalizer,供 OpenAI relay 的 EOF 收尾路径调用。

本 PR 仅修改两个源码文件,不包含测试文件。

#5345 的区别:该 PR 修改的是重构前的 service/convert.go 路径;本 PR 针对当前 relaykit 架构下无 finish_reason 终止 chunk 的 [DONE]/EOF 收尾路径,不改变正常终止 chunk 的 usage 处理逻辑。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix)
  • ✨ 新功能 (New feature)
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

✅ 提交前检查项 / Checklist

  • 非重复提交: 已检索现有 Issues 与 PRs,并在变更描述中说明与相近 PR 的差异。
  • Bug fix 说明: 已关联相同结束事件缺失症状的 Issue。
  • 变更理解: 已确认 EOF 收尾路径通过现有 finalizer 生成完整 Claude SSE 生命周期。
  • 范围聚焦: 本 PR 仅包含两个相关源码文件的修改。
  • 本地验证: 已通过包级编译检查。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

$ GOWORK=off go test -vet=off ./relay/channel/openai -run '^$' -count=1
ok  github.com/QuantumNous/new-api/relay/channel/openai  0.686s [no tests to run]

Summary by CodeRabbit

  • Bug Fixes
    • Improved Claude response handling when using OpenAI-compatible streaming.
    • Ensured final streamed responses are emitted correctly after conversion completes.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The change adds an exported OpenAI-to-Claude stream finalization wrapper. Claude final-response handling now invokes the wrapper after processing converted stream responses and emits the finalized responses.

Changes

OpenAI-to-Claude stream finalization

Layer / File(s) Summary
Finalize converted Claude responses
relaykit/relayconvert/response_compat.go, relay/channel/openai/helper.go
The compatibility layer exposes FinalizeStreamResponseOpenAI2Claude. Claude final-response handling invokes it after converted responses and removes the previous completion-state assignment.

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

Possibly related PRs

Suggested reviewers: calcium-ion

Poem

A rabbit hops through streams of light,
Claude responses finish right.
A wrapper opens the final gate,
Converted words no longer wait.
The final signal joins the flow—
Hop, hop, done! Off we go.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: finalizing Claude streams after upstream EOF.
✨ 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.

🧹 Nitpick comments (1)
relay/channel/openai/helper.go (1)

197-199: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Add regression coverage for the final SSE sequence.

Test a final normal chunk without finish_reason, followed by finalization. Assert content_block_stop, message_delta, and message_stop.

Also test a chunk that already completes conversion. Assert that the finalizer emits no duplicate events after Done is set. The PR adds no tests. (github.com)

🤖 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/channel/openai/helper.go` around lines 197 - 199, Add regression tests
covering FinalizeStreamResponseOpenAI2Claude and the helper.ClaudeData flow:
verify a final normal chunk without finish_reason followed by finalization emits
content_block_stop, message_delta, and message_stop, and verify an
already-completed chunk causes no duplicate events after Done is set.
🤖 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/channel/openai/helper.go`:
- Around line 197-199: Add regression tests covering
FinalizeStreamResponseOpenAI2Claude and the helper.ClaudeData flow: verify a
final normal chunk without finish_reason followed by finalization emits
content_block_stop, message_delta, and message_stop, and verify an
already-completed chunk causes no duplicate events after Done is set.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 88f13e74-68bb-414c-be3b-4764cfd98469

📥 Commits

Reviewing files that changed from the base of the PR and between 823e263 and 72b4def.

📒 Files selected for processing (2)
  • relay/channel/openai/helper.go
  • relaykit/relayconvert/response_compat.go

@kuangzhenfeng
kuangzhenfeng marked this pull request as ready for review August 8, 2026 08:23
ishalumi added a commit to ishalumi/new-api that referenced this pull request Aug 19, 2026
)

messages 请求走 openai 渠道时,上游 EOF 若没有 usage-only chunk,
message_delta/message_stop 会被 defer 后丢失,导致 Claude Code 收不到
tool_use 终止信号、无法发起第二轮 tool 调用(会话断流)。

接线 FinalizeStreamResponseOpenAI2Claude 补发终止事件,含 isha patches。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant