@@ -2,6 +2,7 @@ package anthropic
22
33import (
44 "encoding/json"
5+ "strings"
56 "testing"
67
78 "github.com/docker/cagent/pkg/chat"
@@ -118,3 +119,91 @@ func TestConvertMessages_AssistantToolCalls_NoText_IncludesToolUse(t *testing.T)
118119 t .Fatalf ("expected content block type 'tool_use', got %v" , typ )
119120 }
120121}
122+
123+ func TestSystemMessages_AreExtractedAndNotInMessageList (t * testing.T ) {
124+ msgs := []chat.Message {
125+ {Role : chat .MessageRoleSystem , Content : " system rules here " },
126+ {Role : chat .MessageRoleUser , Content : "hi" },
127+ }
128+
129+ // System blocks should be extracted
130+ sys := extractSystemBlocks (msgs )
131+ if len (sys ) != 1 {
132+ t .Fatalf ("expected 1 system block, got %d" , len (sys ))
133+ }
134+ if strings .TrimSpace (sys [0 ].Text ) != "system rules here" {
135+ t .Fatalf ("unexpected system text: %q" , sys [0 ].Text )
136+ }
137+
138+ // System role messages must not appear in the anthropic messages list
139+ out := convertMessages (msgs )
140+ if len (out ) != 1 {
141+ t .Fatalf ("expected 1 non-system message, got %d" , len (out ))
142+ }
143+ }
144+
145+ func TestSystemMessages_MultipleExtractedAndExcludedFromMessageList (t * testing.T ) {
146+ msgs := []chat.Message {
147+ {Role : chat .MessageRoleSystem , Content : " sys A " },
148+ {Role : chat .MessageRoleSystem , Content : "\n sys B \t " },
149+ {Role : chat .MessageRoleUser , Content : "hello" },
150+ }
151+
152+ sys := extractSystemBlocks (msgs )
153+ if len (sys ) != 2 {
154+ t .Fatalf ("expected 2 system blocks, got %d" , len (sys ))
155+ }
156+ if strings .TrimSpace (sys [0 ].Text ) != "sys A" {
157+ t .Fatalf ("unexpected first system text: %q" , sys [0 ].Text )
158+ }
159+ if strings .TrimSpace (sys [1 ].Text ) != "sys B" {
160+ t .Fatalf ("unexpected second system text: %q" , sys [1 ].Text )
161+ }
162+
163+ out := convertMessages (msgs )
164+ if len (out ) != 1 {
165+ t .Fatalf ("expected 1 non-system message, got %d" , len (out ))
166+ }
167+ }
168+
169+ func TestSystemMessages_InterspersedExtractedAndExcluded (t * testing.T ) {
170+ msgs := []chat.Message {
171+ {Role : chat .MessageRoleSystem , Content : " S1 " },
172+ {Role : chat .MessageRoleUser , Content : "U1" },
173+ {Role : chat .MessageRoleAssistant , Content : "A1" },
174+ {Role : chat .MessageRoleSystem , Content : "S2" },
175+ {Role : chat .MessageRoleUser , Content : " U2 " },
176+ }
177+
178+ // All system messages should be extracted in order of appearance
179+ sys := extractSystemBlocks (msgs )
180+ if len (sys ) != 2 {
181+ t .Fatalf ("expected 2 system blocks, got %d" , len (sys ))
182+ }
183+ if strings .TrimSpace (sys [0 ].Text ) != "S1" {
184+ t .Fatalf ("unexpected first system text: %q" , sys [0 ].Text )
185+ }
186+ if strings .TrimSpace (sys [1 ].Text ) != "S2" {
187+ t .Fatalf ("unexpected second system text: %q" , sys [1 ].Text )
188+ }
189+
190+ // Converted messages must exclude system roles and preserve order of others
191+ out := convertMessages (msgs )
192+ if len (out ) != 3 {
193+ t .Fatalf ("expected 3 non-system messages, got %d" , len (out ))
194+ }
195+ // Check roles: user, assistant, user
196+ for i , expected := range []string {"user" , "assistant" , "user" } {
197+ b , err := json .Marshal (out [i ])
198+ if err != nil {
199+ t .Fatalf ("marshal error: %v" , err )
200+ }
201+ var m map [string ]any
202+ if err := json .Unmarshal (b , & m ); err != nil {
203+ t .Fatalf ("unmarshal error: %v" , err )
204+ }
205+ if role , _ := m ["role" ].(string ); role != expected {
206+ t .Fatalf ("unexpected role at %d: got %q want %q" , i , role , expected )
207+ }
208+ }
209+ }
0 commit comments