@@ -170,6 +170,14 @@ func ConvertOpenAIResponsesRequestToClaude(modelName string, inputRawJSON []byte
170170
171171 // input array processing
172172 var pendingReasoningParts []string
173+ type pendingToolUseMessage struct {
174+ callID string
175+ raw []byte
176+ }
177+ var pendingToolUseMessages []pendingToolUseMessage
178+ appendMessage := func (msg []byte ) {
179+ out , _ = sjson .SetRawBytes (out , "messages.-1" , msg )
180+ }
173181 flushPendingReasoning := func () {
174182 if len (pendingReasoningParts ) == 0 {
175183 return
@@ -178,9 +186,28 @@ func ConvertOpenAIResponsesRequestToClaude(modelName string, inputRawJSON []byte
178186 for _ , partJSON := range pendingReasoningParts {
179187 asst , _ = sjson .SetRawBytes (asst , "content.-1" , []byte (partJSON ))
180188 }
181- out , _ = sjson . SetRawBytes ( out , "messages.-1" , asst )
189+ appendMessage ( asst )
182190 pendingReasoningParts = nil
183191 }
192+ flushPendingToolUses := func () {
193+ for _ , pending := range pendingToolUseMessages {
194+ appendMessage (pending .raw )
195+ }
196+ pendingToolUseMessages = nil
197+ }
198+ flushPendingToolUseFor := func (callID string ) {
199+ if len (pendingToolUseMessages ) == 0 {
200+ return
201+ }
202+ for i , pending := range pendingToolUseMessages {
203+ if pending .callID == callID {
204+ appendMessage (pending .raw )
205+ pendingToolUseMessages = append (pendingToolUseMessages [:i ], pendingToolUseMessages [i + 1 :]... )
206+ return
207+ }
208+ }
209+ flushPendingToolUses ()
210+ }
184211
185212 if input := root .Get ("input" ); input .Exists () && input .IsArray () {
186213 input .ForEach (func (_ , item gjson.Result ) bool {
@@ -294,6 +321,9 @@ func ConvertOpenAIResponsesRequestToClaude(modelName string, inputRawJSON []byte
294321 }
295322
296323 hasReasoningParts := false
324+ if role != "assistant" {
325+ flushPendingToolUses ()
326+ }
297327 if len (pendingReasoningParts ) > 0 {
298328 if role == "assistant" {
299329 if len (partsJSON ) == 0 && textAggregate .Len () > 0 {
@@ -322,12 +352,12 @@ func ConvertOpenAIResponsesRequestToClaude(modelName string, inputRawJSON []byte
322352 msg , _ = sjson .SetRawBytes (msg , "content.-1" , []byte (partJSON ))
323353 }
324354 }
325- out , _ = sjson . SetRawBytes ( out , "messages.-1" , msg )
355+ appendMessage ( msg )
326356 } else if textAggregate .Len () > 0 || role == "system" {
327357 msg := []byte (`{"role":"","content":""}` )
328358 msg , _ = sjson .SetBytes (msg , "role" , role )
329359 msg , _ = sjson .SetBytes (msg , "content" , textAggregate .String ())
330- out , _ = sjson . SetRawBytes ( out , "messages.-1" , msg )
360+ appendMessage ( msg )
331361 }
332362
333363 case "reasoning" :
@@ -360,25 +390,30 @@ func ConvertOpenAIResponsesRequestToClaude(modelName string, inputRawJSON []byte
360390 }
361391 pendingReasoningParts = nil
362392 asst , _ = sjson .SetRawBytes (asst , "content.-1" , toolUse )
363- out , _ = sjson .SetRawBytes (out , "messages.-1" , asst )
393+ pendingToolUseMessages = append (pendingToolUseMessages , pendingToolUseMessage {
394+ callID : callID ,
395+ raw : asst ,
396+ })
364397
365398 case "function_call_output" :
366399 flushPendingReasoning ()
367400 // Map to user tool_result
368401 callID := item .Get ("call_id" ).String ()
402+ flushPendingToolUseFor (callID )
369403 outputStr := item .Get ("output" ).String ()
370404 toolResult := []byte (`{"type":"tool_result","tool_use_id":"","content":""}` )
371405 toolResult , _ = sjson .SetBytes (toolResult , "tool_use_id" , callID )
372406 toolResult , _ = sjson .SetBytes (toolResult , "content" , outputStr )
373407
374408 usr := []byte (`{"role":"user","content":[]}` )
375409 usr , _ = sjson .SetRawBytes (usr , "content.-1" , toolResult )
376- out , _ = sjson . SetRawBytes ( out , "messages.-1" , usr )
410+ appendMessage ( usr )
377411 }
378412 return true
379413 })
380414 }
381415 flushPendingReasoning ()
416+ flushPendingToolUses ()
382417
383418 includedToolNames := map [string ]struct {}{}
384419 toolNameMap := map [string ]string {}
0 commit comments