@@ -322,15 +322,50 @@ def merge_user_messages(messages: List[Dict[str, Any]], hint: str = THINKING_HIN
322322
323323 return result
324324
325+ def _reorder_tool_results_by_tool_uses (tool_results : List [Dict [str , Any ]], tool_use_order : List [str ]) -> List [Dict [str , Any ]]:
326+ """Reorder tool_results to match the order of tool_uses from the preceding assistant message.
327+
328+ This is critical for preventing model confusion when parallel tool calls return results
329+ in a different order than they were called.
330+
331+ Args:
332+ tool_results: List of tool_result dicts with toolUseId
333+ tool_use_order: List of toolUseIds in the order they appeared in the assistant message
334+
335+ Returns:
336+ Reordered list of tool_results
337+ """
338+ if not tool_use_order or not tool_results :
339+ return tool_results
340+
341+ result_by_id = {r ["toolUseId" ]: r for r in tool_results }
342+ ordered_results = []
343+
344+ # Add results in the order of tool_uses
345+ for tool_use_id in tool_use_order :
346+ if tool_use_id in result_by_id :
347+ ordered_results .append (result_by_id .pop (tool_use_id ))
348+
349+ # Add any remaining results not in the original order (shouldn't happen normally)
350+ ordered_results .extend (result_by_id .values ())
351+
352+ return ordered_results
353+
354+
325355def process_history (messages : List [ClaudeMessage ], thinking_enabled : bool = False , hint : str = THINKING_HINT ) -> List [Dict [str , Any ]]:
326356 """Process history messages to match Amazon Q format (alternating user/assistant).
327357
328358 Dual-mode detection:
329359 - If messages already alternate correctly (no consecutive user/assistant), skip merging
330360 - If messages have consecutive same-role messages, apply merge logic
361+
362+ Key fix: Track tool_use order from assistant messages and reorder tool_results in user
363+ messages to match. This prevents model confusion when parallel tool calls return results
364+ in a different order than they were called.
331365 """
332366 history = []
333367 seen_tool_use_ids = set () # Track tool_use IDs in assistant messages
368+ last_tool_use_order = [] # Track order of tool_uses from the last assistant message
334369
335370 raw_history = []
336371
@@ -369,10 +404,15 @@ def process_history(messages: List[ClaudeMessage], thinking_enabled: bool = Fals
369404 text_content = "\n " .join (text_parts )
370405 else :
371406 text_content = extract_text_from_content (content )
372-
407+
373408 if should_append_hint :
374409 text_content = _append_thinking_hint (text_content , hint )
375-
410+
411+ # Reorder tool_results to match the order of tool_uses from the preceding assistant message
412+ if tool_results and last_tool_use_order :
413+ tool_results = _reorder_tool_results_by_tool_uses (tool_results , last_tool_use_order )
414+ logger .info (f"Reordered { len (tool_results )} tool_results to match tool_uses order" )
415+
376416 user_ctx = {
377417 "envState" : {
378418 "operatingSystem" : "macos" ,
@@ -389,35 +429,38 @@ def process_history(messages: List[ClaudeMessage], thinking_enabled: bool = Fals
389429 }
390430 if images :
391431 u_msg ["images" ] = images
392-
432+
393433 raw_history .append ({"userInputMessage" : u_msg })
394-
434+
395435 elif msg .role == "assistant" :
396436 content = msg .content
397437 text_content = extract_text_from_content (content )
398-
438+
399439 entry = {
400440 "assistantResponseMessage" : {
401441 "messageId" : str (uuid .uuid4 ()),
402442 "content" : text_content
403443 }
404444 }
405-
445+
446+ # Track tool_use order for reordering tool_results in the next user message
447+ last_tool_use_order = []
406448 if isinstance (content , list ):
407449 tool_uses = []
408450 for block in content :
409451 if isinstance (block , dict ) and block .get ("type" ) == "tool_use" :
410452 tid = block .get ("id" )
411453 if tid and tid not in seen_tool_use_ids :
412454 seen_tool_use_ids .add (tid )
455+ last_tool_use_order .append (tid ) # Track order
413456 tool_uses .append ({
414457 "toolUseId" : tid ,
415458 "name" : block .get ("name" ),
416459 "input" : block .get ("input" , {})
417460 })
418461 if tool_uses :
419462 entry ["assistantResponseMessage" ]["toolUses" ] = tool_uses
420-
463+
421464 raw_history .append (entry )
422465
423466 # Dual-mode detection: check if messages already alternate correctly
@@ -589,6 +632,26 @@ def convert_claude_to_amazonq_request(req: ClaudeRequest, conversation_id: Optio
589632 else :
590633 prompt_content = extract_text_from_content (content )
591634
635+ # Get tool_use order from the last assistant message for reordering current message's tool_results
636+ last_tool_use_order = []
637+ if len (req .messages ) >= 2 :
638+ # Find the last assistant message before the current user message
639+ for i in range (len (req .messages ) - 2 , - 1 , - 1 ):
640+ if req .messages [i ].role == "assistant" :
641+ assistant_content = req .messages [i ].content
642+ if isinstance (assistant_content , list ):
643+ for block in assistant_content :
644+ if isinstance (block , dict ) and block .get ("type" ) == "tool_use" :
645+ tid = block .get ("id" )
646+ if tid :
647+ last_tool_use_order .append (tid )
648+ break
649+
650+ # Reorder tool_results to match the order of tool_uses from the preceding assistant message
651+ if tool_results and last_tool_use_order :
652+ tool_results = _reorder_tool_results_by_tool_uses (tool_results , last_tool_use_order )
653+ logger .info (f"Reordered { len (tool_results )} current message tool_results to match tool_uses order" )
654+
592655 # 3. Context
593656 user_ctx = {
594657 "envState" : {
0 commit comments