feat: add Claude upstream stream aggregation#5025
Conversation
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds a force-upstream-stream channel setting, RelayInfo upstream-stream decision and JSON injection, handler/adaptor wiring to enable upstream streaming, Claude SSE aggregation into non-stream JSON responses, media-file conversion improvements, optional streaming timeout handling, UI schema + toggles + translations, tests, and docs. ChangesUpstream streaming core feature
Stream scanner timeout optimization
Classic web UI channel configuration
Default web UI channel configuration and i18n
Docs and controller test
Sequence Diagram(s) sequenceDiagram
participant Client
participant Adaptor as Relay Claude Adaptor
participant Upstream as Claude Upstream
participant Agg as AggregateClaudeStreamResponse
Client->>Adaptor: Non-stream request
Adaptor->>Upstream: Upstream request (stream:true injected when UpstreamStream)
Upstream-->>Adaptor: SSE stream (text/event-stream)
Adaptor->>Agg: Pass HTTP response + RelayInfo
Agg->>Agg: Parse SSE "data:" events, aggregate text/tool-use/stop_sequence
Agg->>Adaptor: Aggregated JSON + usage
Adaptor->>Client: Single JSON response (non-stream)
Estimated code review effort 🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
Co-authored-by: Codex <noreply@openai.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
web/default/src/i18n/locales/zh.json (1)
1209-1209: ⚡ Quick winUse semantic hierarchical i18n keys for these new entries.
These newly added translation keys are sentence-based; please switch to hierarchical semantic keys (for example under a
channels.claude.*namespace) to keep i18n naming consistent and maintainable.As per coding guidelines,
web/default/src/i18n/**/*.{ts,tsx,json}should “Use hierarchical and semantically clear translation key names such asdashboard.overview.titleand maintain naming consistency”.Also applies to: 1791-1791, 4232-4232
🤖 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 `@web/default/src/i18n/locales/zh.json` at line 1209, Replace the sentence-based JSON key "Disabled while request body pass-through is enabled" with a hierarchical semantic key under an appropriate namespace (e.g., channels.claude.requestBody.passThroughDisabled or channels.claude.disabledRequestBodyPassThrough) and move the existing Chinese value "请求体透传开启时,此开关会失效" to that new key; update any references to this string in code to use the new key name and apply the same pattern for the other mentioned entries (lines ~1791 and ~4232) to ensure consistent hierarchical i18n naming.
🤖 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 `@web/classic/src/i18n/locales/ja.json`:
- Around line 1024-1026: The three new translation entries ("强制上游流式",
"请求体透传开启时,此开关会失效", "当下游请求为非流式时,此 Claude 渠道与上游之间使用流式通信") use 「上流」「下流」; update
their Japanese values to use the consistent terminology 「アップストリーム」「ダウンストリーム」
(e.g., change "上流ストリーミングを強制" → "アップストリームストリーミングを強制",
"リクエストボディのパススルーが有効な間、このスイッチは無効になります" keep same but ensure any occurrence of
上流/下流 is converted, and "下流リクエストが非ストリーミングの場合、この Claude
チャネルと上流の間でストリーミング通信を使用します" → use "ダウンストリーム" and "アップストリーム" accordingly) so the
file matches existing terminology.
In `@web/default/src/i18n/locales/vi.json`:
- Line 4232: Update the Vietnamese translation value for the JSON key "Use
streaming between this Claude channel and upstream for non-streaming downstream
requests" to replace the phrase "phía dưới" with the clearer technical term "hạ
nguồn" so the string reads: "Dùng truyền phát giữa kênh Claude này và thượng
nguồn cho các yêu cầu phía hạ nguồn không truyền phát" (or equivalent ordering
that uses "hạ nguồn"); edit the value in vi.json for that exact key.
---
Nitpick comments:
In `@web/default/src/i18n/locales/zh.json`:
- Line 1209: Replace the sentence-based JSON key "Disabled while request body
pass-through is enabled" with a hierarchical semantic key under an appropriate
namespace (e.g., channels.claude.requestBody.passThroughDisabled or
channels.claude.disabledRequestBodyPassThrough) and move the existing Chinese
value "请求体透传开启时,此开关会失效" to that new key; update any references to this string in
code to use the new key name and apply the same pattern for the other mentioned
entries (lines ~1791 and ~4232) to ensure consistent hierarchical i18n naming.
🪄 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: abb37541-a929-47a9-8811-7cc95a2647b6
📒 Files selected for processing (29)
dto/channel_settings.godto/claude.gorelay/channel/claude/adaptor.gorelay/channel/claude/relay-claude.gorelay/channel/claude/relay_claude_test.gorelay/claude_handler.gorelay/common/relay_info.gorelay/common/relay_info_test.gorelay/compatible_handler.gorelay/helper/stream_scanner.gorelay/helper/stream_scanner_test.goweb/classic/src/components/table/channels/modals/EditChannelModal.jsxweb/classic/src/i18n/locales/en.jsonweb/classic/src/i18n/locales/fr.jsonweb/classic/src/i18n/locales/ja.jsonweb/classic/src/i18n/locales/ru.jsonweb/classic/src/i18n/locales/vi.jsonweb/classic/src/i18n/locales/zh-CN.jsonweb/classic/src/i18n/locales/zh-TW.jsonweb/classic/src/i18n/locales/zh.jsonweb/default/src/features/channels/components/drawers/channel-mutate-drawer.tsxweb/default/src/features/channels/lib/channel-form.tsweb/default/src/features/channels/types.tsweb/default/src/i18n/locales/en.jsonweb/default/src/i18n/locales/fr.jsonweb/default/src/i18n/locales/ja.jsonweb/default/src/i18n/locales/ru.jsonweb/default/src/i18n/locales/vi.jsonweb/default/src/i18n/locales/zh.json
panjinhe
left a comment
There was a problem hiding this comment.
Reviewed locally: diff checked, combined merge tested with related PRs, targeted tests passed.
panjinhe
left a comment
There was a problem hiding this comment.
Reviewed locally: diff checked, combined merge tested with related PRs, targeted tests passed.
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
web/default/src/i18n/locales/en.json (1)
1216-1216: 🏗️ Heavy liftUse semantic hierarchical i18n keys instead of sentence-as-key entries.
The new entries still use literal English phrases as keys (e.g., Line 1216, Line 1800, Line 4266). Please migrate these additions to namespaced semantic keys (for example,
channels.form.forceUpstreamStream.label,channels.form.forceUpstreamStream.disabledReason,channels.form.forceUpstreamStream.description) and keep naming consistent with the same convention across locales.As per coding guidelines, "
web/default/src/i18n/**/*.{ts,tsx,json}: Use hierarchical and semantically clear translation key names such asdashboard.overview.titleand maintain naming consistency".Also applies to: 1800-1800, 4266-4266
🤖 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 `@web/default/src/i18n/locales/en.json` at line 1216, The JSON contains sentence-as-key entries like "Disabled while request body pass-through is enabled"; replace these with hierarchical semantic keys (e.g., channels.form.forceUpstreamStream.disabledReason) and move the English string to the value side of that key; update similar entries at the other mentioned locations (lines with literal keys) to follow the same convention and naming pattern (for example channels.form.forceUpstreamStream.label and channels.form.forceUpstreamStream.description) so all locales use consistent, namespaced keys.
🤖 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 `@web/default/src/i18n/locales/en.json`:
- Line 1216: The JSON contains sentence-as-key entries like "Disabled while
request body pass-through is enabled"; replace these with hierarchical semantic
keys (e.g., channels.form.forceUpstreamStream.disabledReason) and move the
English string to the value side of that key; update similar entries at the
other mentioned locations (lines with literal keys) to follow the same
convention and naming pattern (for example
channels.form.forceUpstreamStream.label and
channels.form.forceUpstreamStream.description) so all locales use consistent,
namespaced keys.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2de7bf8e-eb3d-4d72-8542-677a5c02562e
📒 Files selected for processing (10)
controller/model_list_test.gorelay/common/relay_info.goweb/classic/src/i18n/locales/en.jsonweb/classic/src/i18n/locales/zh.jsonweb/default/src/i18n/locales/en.jsonweb/default/src/i18n/locales/fr.jsonweb/default/src/i18n/locales/ja.jsonweb/default/src/i18n/locales/ru.jsonweb/default/src/i18n/locales/vi.jsonweb/default/src/i18n/locales/zh.json
✅ Files skipped from review due to trivial changes (5)
- web/classic/src/i18n/locales/zh.json
- web/default/src/i18n/locales/vi.json
- web/default/src/i18n/locales/ru.json
- web/default/src/i18n/locales/zh.json
- web/classic/src/i18n/locales/en.json
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
📝 变更描述 / Description
为 Claude 渠道增加“强制上游流式”配置:当下游请求是非流式时,new-api 与 Claude 上游之间可以改用流式通信,并在服务端聚合为下游期望的非流式响应。
这样做的原因是站点之间的连接经常经过 CDN 加速域名或负载均衡域名。非流式长耗时请求在上游长时间没有响应数据时,容易被 CDN 或负载均衡判定为空闲连接并断开;改为上游流式后,连接过程中会持续有 SSE 数据返回,可以降低这类中间层断连风险,同时保持下游接口仍是非流式响应。
本 PR 同时补充了前端渠道配置开关,并处理注意事项:部分渠道设置会使本开关失效,例如“请求体透传”。当请求体透传开启时,前端会自动关闭并禁用“强制上游流式”开关,保存时也会写入
force_upstream_stream: false,与后端门控保持一致。另外单独修复 Claude OpenAI file content 转换,使 PDF/text file content 能正确转换到 Claude 消息结构。
已更新
docs/channel/other_setting.md,补充force_upstream_stream、pass_through_body_enabled以及两者互斥关系。🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。📸 运行证明 / Proof of Work
new switch in channel configuration:

my newapi log:
upstream newapi log:
go test ./...cd web/default bun run typecheck补充说明:
cd web/default && bun run format:check当前会因仓库既有未格式化文件失败;本 PR 仅对触碰到的 default 前端文件运行了 prettier。Summary by CodeRabbit
New Features
Behavior
Tests
Docs