Skip to content

fix: aws text content blocks must be non-empty - #3077

Merged
seefs001 merged 3 commits into
QuantumNous:mainfrom
seefs001:fix/aws-non-empty-text
Mar 2, 2026
Merged

fix: aws text content blocks must be non-empty#3077
seefs001 merged 3 commits into
QuantumNous:mainfrom
seefs001:fix/aws-non-empty-text

Conversation

@seefs001

@seefs001 seefs001 commented Mar 2, 2026

Copy link
Copy Markdown
Collaborator

fix #1854

@coderabbitai

coderabbitai Bot commented Mar 2, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This PR enhances Claude relay message handling to safely process tool calls with empty or malformed arguments. It updates assistant message construction to use null content when appropriate, implements safer JSON parsing for tool-call arguments with empty map defaults, and expands test coverage with new scenarios for tool-call translation and streaming paths.

Changes

Cohort / File(s) Summary
Claude Tool-Call Handling
relay/channel/claude/relay-claude.go
Updated assistant message construction to set null content when tool calls are present with empty content; implemented safer JSON parsing for tool-call arguments using UnmarshalJsonStr helper with fallback to empty maps; ensured Claude-to-OpenAI streaming paths compute valid JSON defaults for function arguments.
Test Coverage and Assertions
relay/channel/claude/relay_claude_test.go
Refactored existing test assertions to use testify helpers (require/assert); added new test cases for OpenAI-to-Claude translation with assistant tool calls (both valid and malformed arguments); added new streaming path tests validating empty and non-empty JSON delta handling for tool calls.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Calcium-Ion

Poem

🐰 A rabbit hops through tool-call land,
Where empty maps now firmly stand,
No more strange placeholders here,
Just safe JSON, crystal clear,
Tool calls now thrive without a fear! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The pull request title references 'aws text content blocks' but the actual changes focus on Claude API message handling and tool call processing, not AWS-specific functionality. Update the title to accurately reflect the main changes, such as 'fix: handle empty content in Claude assistant messages with tool calls' or similar.
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 (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
relay/channel/claude/relay-claude.go (1)

251-265: ⚠️ Potential issue | 🟠 Major

Use non-empty tool-call checks instead of non-nil checks.

At Line 251 and Line 264, message.ToolCalls != nil treats an empty slice as a real tool-call message. That can bypass the "..." fallback and produce empty assistant content blocks, which can still trigger upstream validation failures.

💡 Suggested fix
 for i, message := range textRequest.Messages {
   if message.Role == "" {
     textRequest.Messages[i].Role = "user"
   }
+  hasAssistantToolCalls := message.Role == "assistant" && len(message.ParseToolCalls()) > 0
+
   fmtMessage := dto.Message{
     Role:    message.Role,
     Content: message.Content,
   }
@@
-  if message.Role == "assistant" && message.ToolCalls != nil {
+  if hasAssistantToolCalls {
     fmtMessage.ToolCalls = message.ToolCalls
     if message.IsStringContent() && message.StringContent() == "" {
       fmtMessage.SetNullContent()
     }
   }
@@
-  if fmtMessage.Content == nil && !(message.Role == "assistant" && message.ToolCalls != nil) {
+  if fmtMessage.Content == nil && !hasAssistantToolCalls {
     fmtMessage.SetStringContent("...")
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@relay/channel/claude/relay-claude.go` around lines 251 - 265, The code
currently checks message.ToolCalls != nil which treats empty slices as valid
tool-call messages and can bypass the "..." fallback; update both occurrences to
use a non-empty check (len(message.ToolCalls) > 0) instead of != nil — i.e.,
change the condition in the block that assigns fmtMessage.ToolCalls (the if with
message.Role == "assistant" && message.ToolCalls != nil) and the final fallback
guard (the if checking fmtMessage.Content == nil && !(message.Role ==
"assistant" && message.ToolCalls != nil)) so they read message.Role ==
"assistant" && len(message.ToolCalls) > 0 and !(message.Role == "assistant" &&
len(message.ToolCalls) > 0) respectively; keep the rest of the logic
(fmtMessage.ToolCalls assignment, SetNullContent/SetStringContent) unchanged.
🧹 Nitpick comments (1)
relay/channel/claude/relay_claude_test.go (1)

166-172: Tighten the Text assertion for tool_use blocks.

Line 170-172 currently allows non-nil Text as long as it isn’t empty. If the intended behavior is “no placeholder text for assistant tool calls,” make this strict with assert.Nil.

🧪 Suggested test tightening
- if contentBlocks[0].Text != nil {
-   assert.NotEqual(t, "", *contentBlocks[0].Text)
- }
+ assert.Nil(t, contentBlocks[0].Text)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@relay/channel/claude/relay_claude_test.go` around lines 166 - 172, The test
currently only checks that contentBlocks[0].Text is non-empty when non-nil;
tighten this for tool_use blocks by asserting it is nil for tool calls: locate
the test in relay_claude_test.go where contentBlocks is inspected (the block
that checks Input and Text) and replace the loose non-empty check with a strict
nil assertion for tool_use blocks (e.g., check contentBlocks[0].Type ==
"tool_use" and assert.Nil(t, contentBlocks[0].Text)); leave the existing Input
map type assertion intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@relay/channel/claude/relay-claude.go`:
- Around line 251-265: The code currently checks message.ToolCalls != nil which
treats empty slices as valid tool-call messages and can bypass the "..."
fallback; update both occurrences to use a non-empty check
(len(message.ToolCalls) > 0) instead of != nil — i.e., change the condition in
the block that assigns fmtMessage.ToolCalls (the if with message.Role ==
"assistant" && message.ToolCalls != nil) and the final fallback guard (the if
checking fmtMessage.Content == nil && !(message.Role == "assistant" &&
message.ToolCalls != nil)) so they read message.Role == "assistant" &&
len(message.ToolCalls) > 0 and !(message.Role == "assistant" &&
len(message.ToolCalls) > 0) respectively; keep the rest of the logic
(fmtMessage.ToolCalls assignment, SetNullContent/SetStringContent) unchanged.

---

Nitpick comments:
In `@relay/channel/claude/relay_claude_test.go`:
- Around line 166-172: The test currently only checks that contentBlocks[0].Text
is non-empty when non-nil; tighten this for tool_use blocks by asserting it is
nil for tool calls: locate the test in relay_claude_test.go where contentBlocks
is inspected (the block that checks Input and Text) and replace the loose
non-empty check with a strict nil assertion for tool_use blocks (e.g., check
contentBlocks[0].Type == "tool_use" and assert.Nil(t, contentBlocks[0].Text));
leave the existing Input map type assertion intact.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96264d2 and 550fbe5.

📒 Files selected for processing (2)
  • relay/channel/claude/relay-claude.go
  • relay/channel/claude/relay_claude_test.go

@seefs001
seefs001 merged commit 1043a30 into QuantumNous:main Mar 2, 2026
1 check passed
@coderabbitai coderabbitai Bot mentioned this pull request Mar 2, 2026
ennnnny pushed a commit to ennnnny/new-api that referenced this pull request Mar 17, 2026
fix: aws text content blocks must be non-empty
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.

Claude code使用new api调用Claude 官方的API模型,会出现报错,导致Claude code 完全无法使用

2 participants