From 4cc7b9b8a92f10d8215e0c114c04db54deec806e Mon Sep 17 00:00:00 2001 From: Christopher Petito Date: Fri, 13 Feb 2026 16:26:05 +0100 Subject: [PATCH] return error if no messages are available after conversion no need to send those requests to the provider since they are invalid Signed-off-by: Christopher Petito --- pkg/model/provider/anthropic/beta_client.go | 3 + pkg/model/provider/anthropic/client.go | 3 + pkg/model/provider/anthropic/client_test.go | 62 +++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/pkg/model/provider/anthropic/beta_client.go b/pkg/model/provider/anthropic/beta_client.go index b99124341..0de36dcba 100644 --- a/pkg/model/provider/anthropic/beta_client.go +++ b/pkg/model/provider/anthropic/beta_client.go @@ -51,6 +51,9 @@ func (c *Client) createBetaStream( return nil, err } } + if len(converted) == 0 { + return nil, errors.New("no messages to send after conversion: all messages were filtered out") + } sys := extractBetaSystemBlocks(messages) diff --git a/pkg/model/provider/anthropic/client.go b/pkg/model/provider/anthropic/client.go index 74e4895e1..fcd10c205 100644 --- a/pkg/model/provider/anthropic/client.go +++ b/pkg/model/provider/anthropic/client.go @@ -280,6 +280,9 @@ func (c *Client) CreateChatCompletionStream( return nil, err } } + if len(converted) == 0 { + return nil, errors.New("no messages to send after conversion: all messages were filtered out") + } sys := extractSystemBlocks(messages) params := anthropic.MessageNewParams{ diff --git a/pkg/model/provider/anthropic/client_test.go b/pkg/model/provider/anthropic/client_test.go index 8e2f56b78..e169bf209 100644 --- a/pkg/model/provider/anthropic/client_test.go +++ b/pkg/model/provider/anthropic/client_test.go @@ -1,6 +1,7 @@ package anthropic import ( + "context" "encoding/json" "net/http" "net/http/httptest" @@ -13,6 +14,8 @@ import ( "github.com/stretchr/testify/require" "github.com/docker/cagent/pkg/chat" + "github.com/docker/cagent/pkg/config/latest" + "github.com/docker/cagent/pkg/model/provider/base" "github.com/docker/cagent/pkg/tools" ) @@ -21,6 +24,65 @@ func testClient() *Client { return &Client{} } +func TestCreateChatCompletionStream_ErrorOnEmptyMessages(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + t.Fatal("request should not have been sent") + w.WriteHeader(http.StatusOK) + })) + defer server.Close() + + client := &Client{ + Config: base.Config{ + ModelConfig: latest.ModelConfig{ + Provider: "anthropic", + Model: "claude-sonnet-4-5-20250929", + }, + }, + clientFn: func(_ context.Context) (anthropic.Client, error) { + return anthropic.NewClient( + option.WithAPIKey("test-key"), + option.WithBaseURL(server.URL), + ), nil + }, + } + + tests := []struct { + name string + messages []chat.Message + }{ + { + name: "nil messages", + messages: nil, + }, + { + name: "empty messages", + messages: []chat.Message{}, + }, + { + name: "only system messages", + messages: []chat.Message{ + {Role: chat.MessageRoleSystem, Content: "You are helpful."}, + }, + }, + { + name: "only whitespace content", + messages: []chat.Message{ + {Role: chat.MessageRoleSystem, Content: "System prompt"}, + {Role: chat.MessageRoleUser, Content: " "}, + {Role: chat.MessageRoleAssistant, Content: " \t\n "}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := client.CreateChatCompletionStream(t.Context(), tt.messages, nil) + require.Error(t, err) + assert.Contains(t, err.Error(), "no messages to send after conversion") + }) + } +} + func TestConvertMessages_SkipEmptySystemText(t *testing.T) { msgs := []chat.Message{{ Role: chat.MessageRoleSystem,