From 05c65d2fe70c16c9671194606d939c5fdd621519 Mon Sep 17 00:00:00 2001 From: Alix-007 Date: Thu, 19 Mar 2026 21:35:17 +0800 Subject: [PATCH] fix(provider): skip empty anthropic tool names (#1772) Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com> --- pkg/providers/anthropic_messages/provider.go | 4 ++ .../anthropic_messages/provider_test.go | 45 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/pkg/providers/anthropic_messages/provider.go b/pkg/providers/anthropic_messages/provider.go index c201dfe00..2b19e941a 100644 --- a/pkg/providers/anthropic_messages/provider.go +++ b/pkg/providers/anthropic_messages/provider.go @@ -221,6 +221,10 @@ func buildRequestBody( // Add tool_use blocks for _, tc := range msg.ToolCalls { + if strings.TrimSpace(tc.Name) == "" { + continue + } + // Handle nil Arguments (GLM-4 may return null input) input := tc.Arguments if input == nil { diff --git a/pkg/providers/anthropic_messages/provider_test.go b/pkg/providers/anthropic_messages/provider_test.go index da4213e92..8eabc15fa 100644 --- a/pkg/providers/anthropic_messages/provider_test.go +++ b/pkg/providers/anthropic_messages/provider_test.go @@ -492,6 +492,20 @@ func TestBuildRequestBodyEdgeCases(t *testing.T) { }, wantErr: false, }, + { + name: "skip tool calls with empty names", + messages: []Message{ + {Role: "assistant", Content: "Calling tool", ToolCalls: []ToolCall{ + {ID: "tool-empty", Name: "", Arguments: map[string]any{"ignored": true}}, + {ID: "tool-valid", Name: "test_tool", Arguments: map[string]any{"arg": "value"}}, + }}, + }, + model: "test-model", + options: map[string]any{ + "max_tokens": 8192, + }, + wantErr: false, + }, } for _, tt := range tests { @@ -513,6 +527,37 @@ func TestBuildRequestBodyEdgeCases(t *testing.T) { if got["model"] != tt.model { t.Errorf("model = %v, want %v", got["model"], tt.model) } + + if tt.name == "skip tool calls with empty names" { + messages, ok := got["messages"].([]any) + if !ok || len(messages) != 1 { + t.Fatalf("messages = %#v, want single assistant message", got["messages"]) + } + + assistantMsg, ok := messages[0].(map[string]any) + if !ok { + t.Fatalf("assistant message = %#v, want map", messages[0]) + } + + content, ok := assistantMsg["content"].([]any) + if !ok { + t.Fatalf("assistant content = %#v, want []any", assistantMsg["content"]) + } + if len(content) != 2 { + t.Fatalf("assistant content length = %d, want 2", len(content)) + } + + toolUse, ok := content[1].(map[string]any) + if !ok { + t.Fatalf("tool_use block = %#v, want map", content[1]) + } + if gotName := toolUse["name"]; gotName != "test_tool" { + t.Fatalf("tool_use name = %v, want %q", gotName, "test_tool") + } + if gotID := toolUse["id"]; gotID != "tool-valid" { + t.Fatalf("tool_use id = %v, want %q", gotID, "tool-valid") + } + } }) } }