fix Claude relay to handle file content blocks to support document types - #2689
fix Claude relay to handle file content blocks to support document types#2689sevenjay wants to merge 4968 commits into
Conversation
…-i2v Gemini Veo3.1[AI Studio]增加图生视频支持
Ensure image file is closed using defer after opening.
…edit Gemini Image系列支持图像编辑
…d-oai feat: 视频下载和界面预览统一使用OAI标准接口
…-err-code fix(aws): extract HTTP status code from AWS SDK errors
…na-err fix: nano-banana not compatible imageSize
…nce-playground-debugging feat(playground): enhance SSE debugging and add image paste support with i18n
fix: nano banana pro 4k(StreamScannerMaxBufferMB env)
feat: glm coding plan && kimi coding plan
…field fix: claude request missing field
fix(i18n): fill missing translations in i18n.
…ix-gemini-ImageConfig Revert "fix: gemini image correct generationConfig"
…emini-veo3.1-i2v Revert "Gemini Veo3.1[AI Studio]增加图生视频支持"
…emini-image-edit Revert "Gemini Image系列支持图像编辑"
…ix-nano-banana-err Revert "fix: nano-banana not compatible imageSize"
问题描述: - 使用 auto 分组的令牌调用 /v1/videos 等 Task 接口时,虽然任务能成功创建, 但使用日志不显示记录,且不会扣费 根本原因: - Distribute 中间件在选择渠道后,会将实际选中的分组存储在 ContextKeyAutoGroup 中 - 但 RelayTaskSubmit 函数没有从 context 中读取这个值来更新 info.UsingGroup - 导致 info.UsingGroup 始终是 "auto" 而不是实际选中的分组(如 "sora2逆") - 当 auto 分组的倍率配置为 0 时,quota 计算结果为 0 - 日志记录条件 "if quota != 0" 不满足,导致日志不记录、不扣费 修复方案: - 在 RelayTaskSubmit 函数中计算分组倍率之前,添加从 ContextKeyAutoGroup 获取实际分组的逻辑 - 使用安全的类型断言,避免潜在的 panic 风险 影响范围: - 仅影响 Task Relay 流程(/v1/videos, /suno, /kling 等接口) - 不影响使用具体分组令牌的调用 - 不影响其他 Relay 类型(chat/completions 等已有类似处理逻辑)
…task-logging fix(task): 修复使用 auto 分组时 Task Relay 不记录日志和不扣费的问题
fix: 设置默认max req body 为128MB
Use the native Gemini Models API (/v1beta/models) instead of the OpenAI-compatible path when listing models for Gemini channels, improving compatibility with third-party Gemini-format providers that don't implement OpenAI routes. - Add paginated model listing with timeout and optional proxy support - Select an enabled key for multi-key Gemini channels
…etchModels fix: remove Minimax from FETCHABLE channels
…tchModels fix(gemini): fetch model list via native v1beta/models endpoint
* feat: /v1/chat/completion -> /v1/response
…-auto-disable feat: status code auto-disable configuration
* fix: setting ui * fix: rm global.chat_completions_to_responses_policy * fix: rm global.chat_completions_to_responses_policy
…Names fix: clean propertyNames for gemini function
…t-param-override feat: channel testing supports parameter overriding
* feat: codex channel * feat: codex channel * feat: codex oauth flow * feat: codex refresh cred * feat: codex usage * fix: codex err message detail * fix: codex setting ui * feat: codex refresh cred task * fix: import err * fix: codex store must be false * fix: chat -> responses tool call * fix: chat -> responses tool call
…sing Claude's rendering logs, the two approaches handle input rendering differently.
…F + plain text) and to guard against nil image/file content so it fails gracefully instead of panicking.
WalkthroughEnhanced Claude message construction in the relay service to support multiple content types: text, image URLs, and files. Added base64 encoding/decoding capabilities, MIME type normalization, and special processing logic for PDF and plain text files. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@relay/channel/claude/relay-claude.go`:
- Around line 389-441: The code misinterprets raw base64 as images because
DecodeBase64FileData expects a data: URI; update the file handling in the
dto.ContentTypeFile branch to explicitly handle "data:" URIs and fail fast for
raw base64: check file.FileData for a "data:" prefix (in addition to the
existing "http" check), pass that through DecodeBase64FileData to obtain
mimeType and base64Data, and if file.FileData is raw base64 (no "data:" and not
an http URL) return a clear error saying the caller must provide a
data:<mime>;base64,<data> URI (or alternatively add a mime field to MessageFile
if you prefer supporting raw base64), preserving the existing logic that maps
"application/pdf" and "text/plain" into dto.ClaudeMessageSource and rejecting
unsupported mime types.
| case dto.ContentTypeFile: | ||
| file := mediaMessage.GetFile() | ||
| if file == nil { | ||
| return nil, fmt.Errorf("file content is empty") | ||
| } | ||
| if file.FileId != "" { | ||
| return nil, fmt.Errorf("file_id is not supported by Claude messages") | ||
| } | ||
| if file.FileData == "" { | ||
| return nil, fmt.Errorf("file_data is empty") | ||
| } | ||
|
|
||
| var ( | ||
| mimeType string | ||
| base64Data string | ||
| err error | ||
| ) | ||
| if strings.HasPrefix(file.FileData, "http") { | ||
| fileData, err := service.GetFileBase64FromUrl(c, file.FileData, "formatting file for Claude") | ||
| if err != nil { | ||
| return nil, fmt.Errorf("get file base64 from url failed: %s", err.Error()) | ||
| } | ||
| mimeType = fileData.MimeType | ||
| base64Data = fileData.Base64Data | ||
| } else { | ||
| mimeType, base64Data, err = service.DecodeBase64FileData(file.FileData) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("decode base64 file data failed: %s", err.Error()) | ||
| } | ||
| } | ||
|
|
||
| mimeType = strings.ToLower(mimeType) | ||
| claudeMediaMessage.Type = "document" | ||
| switch mimeType { | ||
| case "application/pdf": | ||
| claudeMediaMessage.Source = &dto.ClaudeMessageSource{ | ||
| Type: "base64", | ||
| MediaType: mimeType, | ||
| Data: base64Data, | ||
| } | ||
| case "text/plain": | ||
| decoded, err := base64.StdEncoding.DecodeString(base64Data) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("decode plain text file data failed: %s", err.Error()) | ||
| } | ||
| claudeMediaMessage.Source = &dto.ClaudeMessageSource{ | ||
| Type: "text", | ||
| MediaType: mimeType, | ||
| Data: string(decoded), | ||
| } | ||
| default: | ||
| return nil, fmt.Errorf("unsupported file type for Claude documents: %s", mimeType) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, find the FileData definition and its usage patterns
echo "=== Searching for FileData definitions ==="
rg -n -B2 -A2 'FileData\s*string' --type go
echo -e "\n=== Searching for file_data mentions in comments/docs ==="
rg -n -C2 'file_data|file.FileData' --type go | head -100
echo -e "\n=== Looking for ContentTypeFile usage ==="
rg -n -C3 'ContentTypeFile' --type goRepository: QuantumNous/new-api
Length of output: 8001
🏁 Script executed:
#!/bin/bash
# Find the DecodeBase64FileData implementation
echo "=== Finding DecodeBase64FileData implementation ==="
rg -n -B5 -A15 'func.*DecodeBase64FileData' --type go
echo -e "\n=== Finding GetFileBase64FromUrl implementation ==="
rg -n -B5 -A15 'func.*GetFileBase64FromUrl' --type goRepository: QuantumNous/new-api
Length of output: 2503
🏁 Script executed:
#!/bin/bash
# Search for test files related to file handling
echo "=== Finding test files with file/base64 tests ==="
fd -e _test.go | xargs rg -l 'FileData|DecodeBase64FileData|GetFileBase64FromUrl' 2>/dev/null
echo -e "\n=== Searching for example usages or data preparation ==="
rg -n 'FileData.*=' --type go | head -30Repository: QuantumNous/new-api
Length of output: 890
🏁 Script executed:
#!/bin/bash
# Get full DecodeBase64FileData and DecodeBase64ImageData implementations
echo "=== Full DecodeBase64FileData implementation ==="
sed -n '43,80p' service/image.go
echo -e "\n=== Full DecodeBase64ImageData implementation ==="
rg -n -A30 'func DecodeBase64ImageData' service/image.goRepository: QuantumNous/new-api
Length of output: 2455
🏁 Script executed:
#!/bin/bash
# Look for tests or documentation about FileData format expectations
echo "=== Test files mentioning DecodeBase64FileData ==="
fd -e _test.go | xargs rg -l 'DecodeBase64FileData' 2>/dev/null
echo -e "\n=== Example or documentation files ==="
rg -n 'FileData.*format|file_data.*format|base64.*PDF|base64.*text' --type go -iRepository: QuantumNous/new-api
Length of output: 1217
🏁 Script executed:
#!/bin/bash
# Check if data: prefix checking exists elsewhere, per the learning
echo "=== Checking for data: prefix handling patterns ==="
rg -n 'strings.HasPrefix.*"data:"' --type go
echo -e "\n=== Check task_video.go from the learning ==="
rg -n -B5 -A5 'FailReason.*data:' --type goRepository: QuantumNous/new-api
Length of output: 1465
Clarify expected file_data format and add data: URI handling.
DecodeBase64FileData only extracts MIME types from proper data-URIs (data:<mime>;base64,<data>); raw base64 triggers image detection, returning "image/<format>" instead of the expected "application/pdf" or "text/plain". The code checks for "http" prefix at line 406 but doesn't check for "data:" prefix (which the codebase already handles elsewhere). Either require and validate data-URI format with explicit MIME type, add a MIME type parameter to MessageFile, or fail fast with a clear error message about expected format.
🤖 Prompt for AI Agents
In `@relay/channel/claude/relay-claude.go` around lines 389 - 441, The code
misinterprets raw base64 as images because DecodeBase64FileData expects a data:
URI; update the file handling in the dto.ContentTypeFile branch to explicitly
handle "data:" URIs and fail fast for raw base64: check file.FileData for a
"data:" prefix (in addition to the existing "http" check), pass that through
DecodeBase64FileData to obtain mimeType and base64Data, and if file.FileData is
raw base64 (no "data:" and not an http URL) return a clear error saying the
caller must provide a data:<mime>;base64,<data> URI (or alternatively add a mime
field to MessageFile if you prefer supporting raw base64), preserving the
existing logic that maps "application/pdf" and "text/plain" into
dto.ClaudeMessageSource and rejecting unsupported mime types.
fix Claude relay to handle file content blocks as document blocks (PDF + plain text) and to guard against nil image/file content so it fails gracefully instead of panicking.
In the new-api/relay/channel/claude/relay-claude.go, around line 360, if it's not text, it treats it as an image. It doesn't support document types. When you send a non-image file, the imageUrl object can't be extracted, which causes a panic.
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.