Merge pull request #16 from TanLuong/fix-anthropic-empty-assistant-msgs-14206613713378994992

fix(providers/anthropic): skip empty assistant messages to fix tool result matching
This commit is contained in:
Nhat Tan 2026-03-28 22:38:37 +07:00 committed by GitHub
commit 88e3c801dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 41 additions and 0 deletions

View file

@ -253,6 +253,14 @@ func buildRequestBody(
content = append(content, toolUse) content = append(content, toolUse)
} }
// Skip empty assistant messages that have no content and no valid tool calls.
// This prevents breaking the Anthropic API requirement where a user message
// containing tool results must immediately follow the assistant message
// containing the corresponding tool calls.
if len(content) == 0 {
continue
}
apiMessages = append(apiMessages, map[string]any{ apiMessages = append(apiMessages, map[string]any{
"role": "assistant", "role": "assistant",
"content": content, "content": content,

View file

@ -506,6 +506,25 @@ func TestBuildRequestBodyEdgeCases(t *testing.T) {
}, },
wantErr: false, wantErr: false,
}, },
{
name: "skip empty assistant messages",
messages: []Message{
{Role: "user", Content: "hello"},
{Role: "assistant", Content: "", ToolCalls: []ToolCall{}}, // Should be skipped
{Role: "assistant", Content: "valid message", ToolCalls: []ToolCall{}},
{Role: "assistant", Content: "", ToolCalls: []ToolCall{
{ID: "tool-valid", Name: "test_tool", Arguments: map[string]any{"arg": "value"}},
}},
{Role: "assistant", Content: "", ToolCalls: []ToolCall{
{ID: "tool-empty", Name: "", Arguments: map[string]any{"ignored": true}},
}}, // Should be skipped because tool call is empty and content is empty
},
model: "test-model",
options: map[string]any{
"max_tokens": 8192,
},
wantErr: false,
},
} }
for _, tt := range tests { for _, tt := range tests {
@ -558,6 +577,20 @@ func TestBuildRequestBodyEdgeCases(t *testing.T) {
t.Fatalf("tool_use id = %v, want %q", gotID, "tool-valid") t.Fatalf("tool_use id = %v, want %q", gotID, "tool-valid")
} }
} }
if tt.name == "skip empty assistant messages" {
messages, ok := got["messages"].([]any)
if !ok {
t.Fatalf("messages is not []any")
}
if len(messages) != 3 {
t.Fatalf(
"expected 3 API messages (user, assistant with text, assistant with tool_use), got %d: %#v",
len(messages),
messages,
)
}
}
}) })
} }
} }