@@ -126,72 +126,76 @@ func TestAnthropicMessages(t *testing.T) {
126126func TestAnthropicMessagesModelThoughts (t * testing.T ) {
127127 t .Parallel ()
128128
129- t .Run ("thinking captured with builtin tool" , func (t * testing.T ) {
130- t .Parallel ()
131-
132- cases := []struct {
133- name string
134- streaming bool
135- fixture []byte
136- expectedToolCallID string
137- expectedThoughts []string
138- }{
139- {
140- name : "single thinking block/streaming" ,
141- streaming : true ,
142- fixture : fixtures .AntSingleBuiltinTool ,
143- expectedToolCallID : "toolu_01RX68weRSquLx6HUTj65iBo" ,
144- expectedThoughts : []string {"The user wants me to read" },
145- },
146- {
147- name : "single thinking block/blocking" ,
148- streaming : false ,
149- fixture : fixtures .AntSingleBuiltinTool ,
150- expectedToolCallID : "toolu_01AusGgY5aKFhzWrFBv9JfHq" ,
151- expectedThoughts : []string {"The user wants me to read" },
152- },
153- {
154- name : "multiple thinking blocks/streaming" ,
155- streaming : true ,
156- fixture : fixtures .AntMultiThinkingBuiltinTool ,
157- expectedToolCallID : "toolu_01RX68weRSquLx6HUTj65iBo" ,
158- expectedThoughts : []string {"The user wants me to read" , "I should use the Read tool" },
159- },
160- {
161- name : "multiple thinking blocks/blocking" ,
162- streaming : false ,
163- fixture : fixtures .AntMultiThinkingBuiltinTool ,
164- expectedToolCallID : "toolu_01AusGgY5aKFhzWrFBv9JfHq" ,
165- expectedThoughts : []string {"The user wants me to read" , "I should use the Read tool" },
166- },
167- }
129+ cases := []struct {
130+ name string
131+ streaming bool
132+ fixture []byte
133+ expectedToolCallID string
134+ expectedThoughts []string // nil means no tool usages expected at all
135+ }{
136+ {
137+ name : "single thinking block/streaming" ,
138+ streaming : true ,
139+ fixture : fixtures .AntSingleBuiltinTool ,
140+ expectedToolCallID : "toolu_01RX68weRSquLx6HUTj65iBo" ,
141+ expectedThoughts : []string {"The user wants me to read" },
142+ },
143+ {
144+ name : "single thinking block/blocking" ,
145+ streaming : false ,
146+ fixture : fixtures .AntSingleBuiltinTool ,
147+ expectedToolCallID : "toolu_01AusGgY5aKFhzWrFBv9JfHq" ,
148+ expectedThoughts : []string {"The user wants me to read" },
149+ },
150+ {
151+ name : "multiple thinking blocks/streaming" ,
152+ streaming : true ,
153+ fixture : fixtures .AntMultiThinkingBuiltinTool ,
154+ expectedToolCallID : "toolu_01RX68weRSquLx6HUTj65iBo" ,
155+ expectedThoughts : []string {"The user wants me to read" , "I should use the Read tool" },
156+ },
157+ {
158+ name : "multiple thinking blocks/blocking" ,
159+ streaming : false ,
160+ fixture : fixtures .AntMultiThinkingBuiltinTool ,
161+ expectedToolCallID : "toolu_01AusGgY5aKFhzWrFBv9JfHq" ,
162+ expectedThoughts : []string {"The user wants me to read" , "I should use the Read tool" },
163+ },
164+ {
165+ name : "no thoughts without tool calls" ,
166+ streaming : true ,
167+ fixture : fixtures .AntSimple , // This fixture contains thoughts, but they're not associated with tool calls.
168+ },
169+ }
168170
169- for _ , tc := range cases {
170- t .Run (tc .name , func (t * testing.T ) {
171- t .Parallel ()
171+ for _ , tc := range cases {
172+ t .Run (tc .name , func (t * testing.T ) {
173+ t .Parallel ()
172174
173- ctx , cancel := context .WithTimeout (t .Context (), time .Second * 30 )
174- t .Cleanup (cancel )
175+ ctx , cancel := context .WithTimeout (t .Context (), time .Second * 30 )
176+ t .Cleanup (cancel )
175177
176- fix := fixtures .Parse (t , tc .fixture )
177- upstream := newMockUpstream (t , ctx , newFixtureResponse (fix ))
178+ fix := fixtures .Parse (t , tc .fixture )
179+ upstream := newMockUpstream (t , ctx , newFixtureResponse (fix ))
178180
179- bridgeServer := newBridgeTestServer (t , ctx , upstream .URL )
181+ bridgeServer := newBridgeTestServer (t , ctx , upstream .URL )
180182
181- reqBody , err := sjson .SetBytes (fix .Request (), "stream" , tc .streaming )
182- require .NoError (t , err )
183- resp := bridgeServer .makeRequest (t , http .MethodPost , pathAnthropicMessages , reqBody )
184- require .Equal (t , http .StatusOK , resp .StatusCode )
183+ reqBody , err := sjson .SetBytes (fix .Request (), "stream" , tc .streaming )
184+ require .NoError (t , err )
185+ resp := bridgeServer .makeRequest (t , http .MethodPost , pathAnthropicMessages , reqBody )
186+ require .Equal (t , http .StatusOK , resp .StatusCode )
185187
186- if tc .streaming {
187- sp := aibridge .NewSSEParser ()
188- require .NoError (t , sp .Parse (resp .Body ))
189- assert .Contains (t , sp .AllEvents (), "message_start" )
190- assert .Contains (t , sp .AllEvents (), "message_stop" )
191- }
188+ if tc .streaming {
189+ sp := aibridge .NewSSEParser ()
190+ require .NoError (t , sp .Parse (resp .Body ))
191+ assert .Contains (t , sp .AllEvents (), "message_start" )
192+ assert .Contains (t , sp .AllEvents (), "message_stop" )
193+ }
192194
193- // Verify tool usage was recorded with associated model thoughts.
194- toolUsages := bridgeServer .Recorder .RecordedToolUsages ()
195+ toolUsages := bridgeServer .Recorder .RecordedToolUsages ()
196+ if tc .expectedThoughts == nil {
197+ assert .Empty (t , toolUsages )
198+ } else {
195199 require .Len (t , toolUsages , 1 )
196200 assert .Equal (t , "Read" , toolUsages [0 ].Tool )
197201 assert .Equal (t , tc .expectedToolCallID , toolUsages [0 ].ToolCallID )
@@ -200,40 +204,11 @@ func TestAnthropicMessagesModelThoughts(t *testing.T) {
200204 for i , expected := range tc .expectedThoughts {
201205 assert .Contains (t , toolUsages [0 ].ModelThoughts [i ].Content , expected )
202206 }
207+ }
203208
204- bridgeServer .Recorder .VerifyAllInterceptionsEnded (t )
205- })
206- }
207- })
208-
209- t .Run ("no thoughts without tool calls" , func (t * testing.T ) {
210- t .Parallel ()
211-
212- ctx , cancel := context .WithTimeout (t .Context (), time .Second * 30 )
213- t .Cleanup (cancel )
214-
215- // Use the simple fixture which has no tool calls — any thinking blocks
216- // should not be persisted since they can't be associated with a tool call.
217- fix := fixtures .Parse (t , fixtures .AntSimple )
218- upstream := newMockUpstream (t , ctx , newFixtureResponse (fix ))
219-
220- bridgeServer := newBridgeTestServer (t , ctx , upstream .URL )
221-
222- reqBody , err := sjson .SetBytes (fix .Request (), "stream" , true )
223- require .NoError (t , err )
224- resp := bridgeServer .makeRequest (t , http .MethodPost , pathAnthropicMessages , reqBody )
225- require .Equal (t , http .StatusOK , resp .StatusCode )
226-
227- sp := aibridge .NewSSEParser ()
228- require .NoError (t , sp .Parse (resp .Body ))
229-
230- // No tool usages (and therefore no thoughts) should be recorded
231- // when there are no tool calls.
232- toolUsages := bridgeServer .Recorder .RecordedToolUsages ()
233- assert .Empty (t , toolUsages )
234-
235- bridgeServer .Recorder .VerifyAllInterceptionsEnded (t )
236- })
209+ bridgeServer .Recorder .VerifyAllInterceptionsEnded (t )
210+ })
211+ }
237212}
238213
239214func TestAWSBedrockIntegration (t * testing.T ) {
0 commit comments