From 7b9631408fd376bc48119a6d26ebd6407baefb95 Mon Sep 17 00:00:00 2001 From: Deadwalk Date: Mon, 29 Sep 2025 16:51:55 +0800 Subject: [PATCH] fix(anthropic): filter empty content messages to prevent API errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add message content validation in getAndValidateAnthropicRequest - Filter out messages with empty content to prevent 'all messages must have non-empty content' errors - Support both text and non-text content validation (images, tool_use, tool_result) - Add detailed logging for filtered messages - Ensure at least one valid message remains after filtering 修复Anthropic协议空消息内容问题: - 在getAndValidateAnthropicRequest中添加消息内容验证 - 过滤空内容消息以防止'all messages must have non-empty content'错误 - 支持文本和非文本内容验证(图片、工具调用、工具结果) - 为被过滤的消息添加详细日志记录 - 确保过滤后至少保留一条有效消息 --- relay/controller/anthropic.go | 37 ++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/relay/controller/anthropic.go b/relay/controller/anthropic.go index 641eb0f2..937e6a5c 100644 --- a/relay/controller/anthropic.go +++ b/relay/controller/anthropic.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "net/http" + "strings" "github.com/gin-gonic/gin" @@ -128,6 +129,40 @@ func getAndValidateAnthropicRequest(c *gin.Context) (*anthropic.Request, error) anthropicRequest.MaxTokens = 4096 // default max tokens } + // Filter out messages with empty content to prevent API errors + var validMessages []anthropic.Message + ctx := c.Request.Context() + + for i, message := range anthropicRequest.Messages { + hasContent := false + + // Check if message has any non-empty content + for _, content := range message.Content.ToContentArray() { + if content.Type == "text" && strings.TrimSpace(content.Text) != "" { + hasContent = true + break + } else if content.Type != "text" && content.Type != "" { + // Non-text content (like images, tool_use, tool_result) is considered valid + hasContent = true + break + } + } + + if hasContent { + validMessages = append(validMessages, message) + } else { + logger.Warnf(ctx, "Filtered out message at index %d with empty content (role: %s)", i, message.Role) + } + } + + // Update the request with filtered messages + anthropicRequest.Messages = validMessages + + // Ensure we still have at least one message after filtering + if len(anthropicRequest.Messages) == 0 { + return nil, fmt.Errorf("no valid messages found after filtering empty content") + } + return anthropicRequest, nil } @@ -161,7 +196,7 @@ func estimateAnthropicTokens(request *anthropic.Request) int { // Count tokens in messages for _, message := range request.Messages { - for _, content := range message.Content { + for _, content := range message.Content.ToContentArray() { if content.Type == "text" { totalTokens += len(content.Text) / CHARS_PER_TOKEN }