Skip to content

Commit 8a9df15

Browse files
jerry-271828claude
andcommitted
Fix tool_result ordering to match tool_uses order
When Claude Code sends parallel tool calls, the tool_results might be returned in a different order than the tool_uses were made. This causes the model to get confused (e.g., seeing Edit result before Read result even though Read was called first). Key changes: 1. Add _reorder_tool_results_by_tool_uses() helper function 2. Track tool_use order from assistant messages in process_history() 3. Reorder tool_results in user messages to match the preceding assistant message's tool_uses order 4. Apply same fix to current message processing in convert_claude_to_amazonq_request() 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent a6fbd96 commit 8a9df15

1 file changed

Lines changed: 70 additions & 7 deletions

File tree

claude_converter.py

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
325355
def 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

Comments
 (0)