fix(claude): buffer SSE for non-stream clients - #6292
Conversation
WalkthroughClaude relay handling now buffers upstream SSE responses into standard JSON when the client requests non-streaming output. Streaming clients continue receiving SSE, while buffered responses preserve content, tool inputs, usage, stop metadata, and related Claude fields. ChangesClaude SSE buffering
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant ClaudeClient
participant AdaptorDoResponse
participant ClaudeUpstream
participant ClaudeBufferedStreamHandler
participant HandleClaudeResponseData
ClaudeClient->>AdaptorDoResponse: Request stream preference
AdaptorDoResponse->>ClaudeUpstream: Receive Claude response
AdaptorDoResponse->>ClaudeBufferedStreamHandler: Buffer SSE for non-stream client
ClaudeUpstream-->>ClaudeBufferedStreamHandler: Claude SSE events
ClaudeBufferedStreamHandler->>HandleClaudeResponseData: Completed Claude JSON and usage
HandleClaudeResponseData-->>ClaudeClient: JSON response
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
relay/channel/claude/buffered_stream_test.go (1)
75-76: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExercise preservation of a non-null
stop_sequence.The test currently proves only that an absent value is emitted as
null; it would not catch the buffered path dropping an actual stop sequence.Proposed test adjustment
- `data: {"type":"message_delta","delta":{"stop_reason":"tool_use"},"usage":{"output_tokens":9}}`, + `data: {"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":"tool-end"},"usage":{"output_tokens":9}}`, ... stopSequence, exists := responseObject["stop_sequence"] assert.True(t, exists) - assert.Nil(t, stopSequence) + assert.Equal(t, "tool-end", stopSequence)As per coding guidelines, backend tests must protect real behavior and API contracts.
Also applies to: 103-105
🤖 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/claude/buffered_stream_test.go` around lines 75 - 76, Update the buffered stream test’s message_delta fixture and corresponding assertions to include a non-null stop_sequence value, verifying that the buffered path preserves and emits the actual sequence instead of converting or dropping it; apply the same adjustment to the related lines noted in the comment.Source: Coding guidelines
🤖 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/claude/buffered_stream_test.go`:
- Around line 75-76: Update the buffered stream test’s message_delta fixture and
corresponding assertions to include a non-null stop_sequence value, verifying
that the buffered path preserves and emits the actual sequence instead of
converting or dropping it; apply the same adjustment to the related lines noted
in the comment.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a86c09d4-cf37-47dc-b7a8-3b79f104e6dc
📒 Files selected for processing (4)
dto/claude.gorelay/channel/claude/adaptor.gorelay/channel/claude/buffered_stream.gorelay/channel/claude/buffered_stream_test.go
|
Addressed the review nit in 7e7b2b8: the buffered-stream regression test now includes a non-null stop_sequence and verifies the exact value is preserved. go test ./relay/channel/claude passes. |
Important
Note
AI-assisted disclosure: 此实现和初始 PR 草稿由 OpenAI Codex 在仓库所有者请求下协助完成;仓库所有者已人工确认变更内容和影响范围。
📝 变更描述 / Description
Claude Messages 的请求可能声明
stream: false,但部分兼容上游仍返回text/event-stream。现有处理会根据上游 Content-Type 将info.IsStream置为 true,随后把 SSE 直接返回给只接受普通 JSON 的客户端。本变更在这种情况下聚合 Claude SSE 事件,按内容块索引还原 text、thinking/signature 和 tool_use 输入,并合并 message_start/message_delta 中的 usage、stop_reason 与 stop_sequence,最终复用现有非流式响应及计费处理输出标准 Claude Messages JSON。客户端原本请求流式时继续使用现有流式处理器。
🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
📸 运行证明 / Proof of Work
以下命令均已通过:
回归测试覆盖:非流式客户端聚合 SSE 后得到 JSON、usage/thinking/tool_use 字段保留,以及流式客户端仍收到 SSE。