Skip to content

fix Claude relay to handle file content blocks to support document types - #2689

Closed
sevenjay wants to merge 4968 commits into
QuantumNous:mainfrom
sevenjay:fix/claude_relay_to_handle_file
Closed

fix Claude relay to handle file content blocks to support document types#2689
sevenjay wants to merge 4968 commits into
QuantumNous:mainfrom
sevenjay:fix/claude_relay_to_handle_file

Conversation

@sevenjay

@sevenjay sevenjay commented Jan 19, 2026

Copy link
Copy Markdown

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

  • New Features
    • Extended Claude integration to support multiple content types including text, images (with URL and base64-encoded support), and file attachments.
    • Added automatic handling for different file types including PDFs and text documents with proper format validation and conversion.

✏️ Tip: You can customize this high-level summary in your review settings.

feitianbubu and others added 30 commits November 26, 2025 21:56
…-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
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"
seefs001 and others added 25 commits January 5, 2026 23:36
问题描述:
- 使用 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 不记录日志和不扣费的问题
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.
@coderabbitai

coderabbitai Bot commented Jan 19, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Enhanced 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

Cohort / File(s) Summary
Claude Content Type Handling
relay/channel/claude/relay-claude.go
Extended message construction with multi-content-type support: added ContentTypeImageURL handling with validation and base64/URL support; introduced ContentTypeFile handling with MIME type normalization, special cases for application/pdf (base64 transmission) and text/plain (decoded text transmission), and error handling for unsupported types. Added base64 import.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • seefs001

Poem

🐰 A hop and a bound through content types new,
Images dancing and files breaking through,
Base64 whispers, MIME types align,
PDFs and text in perfect design!
The relay hops forward, so clever and bright!

🚥 Pre-merge checks | ✅ 2 | ❌ 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 (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding support for file content blocks (including PDF and plain text documents) to the Claude relay, which directly addresses the panic issue when non-image files were sent.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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 and usage tips.

@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

🤖 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.

Comment on lines +389 to +441
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)
}

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.

⚠️ Potential issue | 🟠 Major

🧩 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 go

Repository: 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 go

Repository: 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 -30

Repository: 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.go

Repository: 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 -i

Repository: 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 go

Repository: 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.

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.