@@ -215,6 +215,158 @@ func (chunk *BedrockStreamEvent) ToBifrostResponsesStream(sequenceNumber int, st
215215 if chunk .Start .ToolUse != nil {
216216 var responses []* schemas.BifrostResponsesStreamResponse
217217
218+ // Close any open reasoning blocks first (Anthropic sends content_block_stop before starting new blocks)
219+ for prevContentIndex := range state .ReasoningContentIndices {
220+ prevOutputIndex , prevExists := state .ContentIndexToOutputIndex [prevContentIndex ]
221+ if ! prevExists {
222+ continue
223+ }
224+
225+ // Skip already completed output indices
226+ if state .CompletedOutputIndices [prevOutputIndex ] {
227+ continue
228+ }
229+
230+ itemID := state .ItemIDs [prevOutputIndex ]
231+
232+ // For reasoning items, content_index is always 0
233+ reasoningContentIndex := 0
234+
235+ // Emit reasoning_summary_text.done
236+ emptyText := ""
237+ reasoningDoneResponse := & schemas.BifrostResponsesStreamResponse {
238+ Type : schemas .ResponsesStreamResponseTypeReasoningSummaryTextDone ,
239+ SequenceNumber : sequenceNumber + len (responses ),
240+ OutputIndex : schemas .Ptr (prevOutputIndex ),
241+ ContentIndex : & reasoningContentIndex ,
242+ Text : & emptyText ,
243+ }
244+ if itemID != "" {
245+ reasoningDoneResponse .ItemID = & itemID
246+ }
247+ responses = append (responses , reasoningDoneResponse )
248+
249+ // Emit content_part.done for reasoning
250+ partDoneResponse := & schemas.BifrostResponsesStreamResponse {
251+ Type : schemas .ResponsesStreamResponseTypeContentPartDone ,
252+ SequenceNumber : sequenceNumber + len (responses ),
253+ OutputIndex : schemas .Ptr (prevOutputIndex ),
254+ ContentIndex : & reasoningContentIndex ,
255+ }
256+ if itemID != "" {
257+ partDoneResponse .ItemID = & itemID
258+ }
259+ responses = append (responses , partDoneResponse )
260+
261+ // Emit output_item.done for reasoning
262+ statusCompleted := "completed"
263+ doneItem := & schemas.ResponsesMessage {
264+ Status : & statusCompleted ,
265+ }
266+ if itemID != "" {
267+ doneItem .ID = & itemID
268+ }
269+ responses = append (responses , & schemas.BifrostResponsesStreamResponse {
270+ Type : schemas .ResponsesStreamResponseTypeOutputItemDone ,
271+ SequenceNumber : sequenceNumber + len (responses ),
272+ OutputIndex : schemas .Ptr (prevOutputIndex ),
273+ ContentIndex : & reasoningContentIndex ,
274+ Item : doneItem ,
275+ })
276+
277+ // Mark this output index as completed
278+ state .CompletedOutputIndices [prevOutputIndex ] = true
279+ }
280+ // Clear reasoning content indices after closing them
281+ clear (state .ReasoningContentIndices )
282+
283+ // Close any open tool call blocks before starting a new one (Anthropic completes each block before starting next)
284+ for prevContentIndex , prevOutputIndex := range state .ContentIndexToOutputIndex {
285+ // Skip reasoning blocks (already handled above)
286+ if state .ReasoningContentIndices [prevContentIndex ] {
287+ continue
288+ }
289+
290+ // Skip already completed output indices
291+ if state .CompletedOutputIndices [prevOutputIndex ] {
292+ continue
293+ }
294+
295+ // Check if this is a tool call
296+ prevToolCallID := state .ToolCallIDs [prevOutputIndex ]
297+ if prevToolCallID == "" {
298+ continue // Not a tool call
299+ }
300+
301+ prevItemID := state .ItemIDs [prevOutputIndex ]
302+ prevToolName := state .ToolCallNames [prevOutputIndex ]
303+ accumulatedArgs := state .ToolArgumentBuffers [prevOutputIndex ]
304+
305+ // Emit content_part.done for tool call
306+ responses = append (responses , & schemas.BifrostResponsesStreamResponse {
307+ Type : schemas .ResponsesStreamResponseTypeContentPartDone ,
308+ SequenceNumber : sequenceNumber + len (responses ),
309+ OutputIndex : schemas .Ptr (prevOutputIndex ),
310+ ContentIndex : schemas .Ptr (prevContentIndex ),
311+ ItemID : & prevItemID ,
312+ })
313+
314+ // Emit function_call_arguments.done with full arguments
315+ if accumulatedArgs != "" {
316+ var doneItem * schemas.ResponsesMessage
317+ if prevToolCallID != "" || prevToolName != "" {
318+ doneItem = & schemas.ResponsesMessage {
319+ ResponsesToolMessage : & schemas.ResponsesToolMessage {},
320+ }
321+ if prevToolCallID != "" {
322+ doneItem .ResponsesToolMessage .CallID = & prevToolCallID
323+ }
324+ if prevToolName != "" {
325+ doneItem .ResponsesToolMessage .Name = & prevToolName
326+ }
327+ }
328+
329+ argsDoneResponse := & schemas.BifrostResponsesStreamResponse {
330+ Type : schemas .ResponsesStreamResponseTypeFunctionCallArgumentsDone ,
331+ SequenceNumber : sequenceNumber + len (responses ),
332+ OutputIndex : schemas .Ptr (prevOutputIndex ),
333+ Arguments : & accumulatedArgs ,
334+ }
335+ if prevItemID != "" {
336+ argsDoneResponse .ItemID = & prevItemID
337+ }
338+ if doneItem != nil {
339+ argsDoneResponse .Item = doneItem
340+ }
341+ responses = append (responses , argsDoneResponse )
342+ }
343+
344+ // Emit output_item.done for tool call
345+ statusCompleted := "completed"
346+ toolDoneItem := & schemas.ResponsesMessage {
347+ ID : & prevItemID ,
348+ Type : schemas .Ptr (schemas .ResponsesMessageTypeFunctionCall ),
349+ Status : & statusCompleted ,
350+ ResponsesToolMessage : & schemas.ResponsesToolMessage {
351+ CallID : & prevToolCallID ,
352+ Name : & prevToolName ,
353+ Arguments : & accumulatedArgs ,
354+ },
355+ }
356+
357+ responses = append (responses , & schemas.BifrostResponsesStreamResponse {
358+ Type : schemas .ResponsesStreamResponseTypeOutputItemDone ,
359+ SequenceNumber : sequenceNumber + len (responses ),
360+ OutputIndex : schemas .Ptr (prevOutputIndex ),
361+ ContentIndex : schemas .Ptr (prevContentIndex ),
362+ ItemID : & prevItemID ,
363+ Item : toolDoneItem ,
364+ })
365+
366+ // Mark this output index as completed
367+ state .CompletedOutputIndices [prevOutputIndex ] = true
368+ }
369+
218370 // Create new output index for this tool use
219371 outputIndex := state .CurrentOutputIndex
220372 state .ContentIndexToOutputIndex [contentBlockIndex ] = outputIndex
0 commit comments