Skip to content

Commit cf6064a

Browse files
authored
Merge pull request #1720 from krissetto/fix-anthropic-empty-messages
return error if no messages are available after conversion
2 parents 68c3cbe + 4cc7b9b commit cf6064a

3 files changed

Lines changed: 68 additions & 0 deletions

File tree

pkg/model/provider/anthropic/beta_client.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ func (c *Client) createBetaStream(
5151
return nil, err
5252
}
5353
}
54+
if len(converted) == 0 {
55+
return nil, errors.New("no messages to send after conversion: all messages were filtered out")
56+
}
5457

5558
sys := extractBetaSystemBlocks(messages)
5659

pkg/model/provider/anthropic/client.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,9 @@ func (c *Client) CreateChatCompletionStream(
280280
return nil, err
281281
}
282282
}
283+
if len(converted) == 0 {
284+
return nil, errors.New("no messages to send after conversion: all messages were filtered out")
285+
}
283286
sys := extractSystemBlocks(messages)
284287

285288
params := anthropic.MessageNewParams{

pkg/model/provider/anthropic/client_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package anthropic
22

33
import (
4+
"context"
45
"encoding/json"
56
"net/http"
67
"net/http/httptest"
@@ -13,6 +14,8 @@ import (
1314
"github.com/stretchr/testify/require"
1415

1516
"github.com/docker/cagent/pkg/chat"
17+
"github.com/docker/cagent/pkg/config/latest"
18+
"github.com/docker/cagent/pkg/model/provider/base"
1619
"github.com/docker/cagent/pkg/tools"
1720
)
1821

@@ -21,6 +24,65 @@ func testClient() *Client {
2124
return &Client{}
2225
}
2326

27+
func TestCreateChatCompletionStream_ErrorOnEmptyMessages(t *testing.T) {
28+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
29+
t.Fatal("request should not have been sent")
30+
w.WriteHeader(http.StatusOK)
31+
}))
32+
defer server.Close()
33+
34+
client := &Client{
35+
Config: base.Config{
36+
ModelConfig: latest.ModelConfig{
37+
Provider: "anthropic",
38+
Model: "claude-sonnet-4-5-20250929",
39+
},
40+
},
41+
clientFn: func(_ context.Context) (anthropic.Client, error) {
42+
return anthropic.NewClient(
43+
option.WithAPIKey("test-key"),
44+
option.WithBaseURL(server.URL),
45+
), nil
46+
},
47+
}
48+
49+
tests := []struct {
50+
name string
51+
messages []chat.Message
52+
}{
53+
{
54+
name: "nil messages",
55+
messages: nil,
56+
},
57+
{
58+
name: "empty messages",
59+
messages: []chat.Message{},
60+
},
61+
{
62+
name: "only system messages",
63+
messages: []chat.Message{
64+
{Role: chat.MessageRoleSystem, Content: "You are helpful."},
65+
},
66+
},
67+
{
68+
name: "only whitespace content",
69+
messages: []chat.Message{
70+
{Role: chat.MessageRoleSystem, Content: "System prompt"},
71+
{Role: chat.MessageRoleUser, Content: " "},
72+
{Role: chat.MessageRoleAssistant, Content: " \t\n "},
73+
},
74+
},
75+
}
76+
77+
for _, tt := range tests {
78+
t.Run(tt.name, func(t *testing.T) {
79+
_, err := client.CreateChatCompletionStream(t.Context(), tt.messages, nil)
80+
require.Error(t, err)
81+
assert.Contains(t, err.Error(), "no messages to send after conversion")
82+
})
83+
}
84+
}
85+
2486
func TestConvertMessages_SkipEmptySystemText(t *testing.T) {
2587
msgs := []chat.Message{{
2688
Role: chat.MessageRoleSystem,

0 commit comments

Comments
 (0)